234 lines
8.5 KiB
JavaScript
234 lines
8.5 KiB
JavaScript
|
|
|
|
const fs = require("fs");
|
|
const os = require("os");
|
|
const path = require("path");
|
|
const { spawnSync } = require("child_process");
|
|
const args = process.argv.slice(2);
|
|
const THIRDPARTY_DIR = __dirname;
|
|
|
|
function findArg(argname, isBoolean) {
|
|
let prefix = `--${argname}`;
|
|
let idx = args.findIndex(arg => arg == prefix);
|
|
if (idx >= 0) {
|
|
if (isBoolean) return true;
|
|
else return args[idx + 1];
|
|
}
|
|
idx = args.findIndex(arg => arg.startsWith(prefix))
|
|
if (idx >= 0) return args[idx].substring(prefix.length + 1);
|
|
return null;
|
|
}
|
|
|
|
function assert(cond, message) {
|
|
if (!cond) {
|
|
console.error(message);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
const buildOptions = {
|
|
withMNN: findArg("with-mnn", true) ?? false,
|
|
withONNX: findArg("with-onnx", true) ?? false,
|
|
buildType: findArg("build-type", false) ?? "Release",
|
|
proxy: findArg("proxy"),
|
|
generator: findArg("generator"),
|
|
}
|
|
|
|
const spawnOption = {
|
|
stdio: "inherit", env: {
|
|
...process.env, ...buildOptions.proxy ? {
|
|
"http_proxy": buildOptions.proxy,
|
|
"https_proxy": buildOptions.proxy,
|
|
} : {}
|
|
}
|
|
};
|
|
|
|
function P(path) { return path.replace(/\\/g, "/"); }
|
|
|
|
function checkFile(...items) {
|
|
return fs.existsSync(path.resolve(...items));
|
|
}
|
|
|
|
function downloadSource(name, repo, branch, recursive, checkedFile) {
|
|
const sourceRootDir = path.join(THIRDPARTY_DIR, "_source");
|
|
fs.mkdirSync(sourceRootDir, { recursive: true });
|
|
const sourceDir = path.join(sourceRootDir, name);
|
|
if (checkFile(sourceDir, checkedFile)) return sourceDir;
|
|
|
|
console.log(`${name}源代码不存在,正在下载...`);
|
|
assert(spawnSync("git", [
|
|
"clone",
|
|
...recursive ? ["--recursive"] : [],
|
|
repo, "-b", branch,
|
|
sourceDir
|
|
], { ...spawnOption }).status == 0, `下载${name}源代码失败`);
|
|
|
|
return sourceDir;
|
|
}
|
|
|
|
function cmakeBuildFromSource(name, repo, branch, downloader, buildArgs, cmakeCreator) {
|
|
const sourceDir = downloader ? downloader(name, repo, branch) : downloadSource(name, repo, branch, false, "CMakeLists.txt");
|
|
const buildDir = path.join(sourceDir, "build", buildOptions.buildType);
|
|
const installDir = path.join(THIRDPARTY_DIR, name, buildOptions.buildType);
|
|
const configFile = path.join(installDir, "config.cmake");
|
|
|
|
if (typeof buildArgs == "function") buildArgs = buildArgs(sourceDir, buildDir, installDir);
|
|
|
|
//编译源代码
|
|
if (checkFile(configFile)) return
|
|
console.log(`${name}目标不存在,正在编译...`);
|
|
fs.rmSync(buildDir, { recursive: true, force: true });
|
|
fs.mkdirSync(buildDir, { recursive: true });
|
|
|
|
assert(spawnSync("cmake", [
|
|
"-G", buildOptions.generator ?? "Ninja", sourceDir,
|
|
"-DCMAKE_BUILD_TYPE=" + buildOptions.buildType,
|
|
"-DCMAKE_INSTALL_PREFIX=" + installDir,
|
|
...(buildArgs ?? []).map(arg => arg.startsWith("-D") ? arg : `-D${arg}`),
|
|
], { ...spawnOption, cwd: buildDir }).status == 0, `配置${name}失败`);
|
|
|
|
assert(spawnSync("cmake", [
|
|
"--build", ".",
|
|
"--parallel", os.cpus().length.toString(),
|
|
"--config", buildOptions.buildType,
|
|
"--target", "install",
|
|
], { ...spawnOption, cwd: buildDir }).status == 0, `编译${name}失败`);
|
|
|
|
fs.writeFileSync(configFile, cmakeCreator(installDir));
|
|
}
|
|
|
|
async function downloadFromURL(name, url, resolver) {
|
|
const cacheDir = path.join(THIRDPARTY_DIR, "_cache");
|
|
fs.mkdirSync(cacheDir, { recursive: true });
|
|
const saveName = path.join(cacheDir, path.basename(url));
|
|
const outputDir = path.join(cacheDir, name);
|
|
fs.rmSync(outputDir, { force: true, recursive: true });
|
|
|
|
if (!checkFile(saveName)) {
|
|
console.log(`开始下载${name}, 地址:${url}`);
|
|
const result = spawnSync("curl", ["-o", saveName + ".cache", "-L", url, "-s", "-w", "%{http_code}"], { ...spawnOption, stdio: "pipe" });
|
|
assert(result.status == 0 && result.stdout.toString() == "200", `下载${name}失败`);
|
|
fs.renameSync(saveName + ".cache", saveName);
|
|
}
|
|
let currentName = saveName;
|
|
|
|
if (saveName.endsWith(".bz2")) {
|
|
currentName = saveName.substring(0, saveName.length - 4);
|
|
const input = fs.createReadStream(saveName);
|
|
const out = fs.createWriteStream(currentName);
|
|
const bz2 = require("unbzip2-stream")();
|
|
await new Promise((resolve, reject) => {
|
|
input.pipe(bz2).pipe(out);
|
|
out.on("close", resolve);
|
|
input.on("error", reject);
|
|
bz2.on("error", reject);
|
|
out.on("error", reject);
|
|
});
|
|
}
|
|
|
|
const format = path.extname(currentName);
|
|
assert([".tar", ".gz", ".tgz", ".zip"].includes(format), "仅支持.tar, .gz, .tgz, .zip格式的压缩文件");
|
|
const method = {
|
|
".tar": require("compressing").tar,
|
|
".gz": require("compressing").gzip,
|
|
".tgz": require("compressing").tgz,
|
|
".zip": require("compressing").zip,
|
|
}[format];
|
|
await method.uncompress(currentName, outputDir);
|
|
|
|
await resolver(outputDir);
|
|
|
|
fs.rmSync(outputDir, { recursive: true, force: true });
|
|
}
|
|
|
|
|
|
async function main() {
|
|
//MNN
|
|
if (buildOptions.withMNN) cmakeBuildFromSource("MNN", "https://github.com/alibaba/MNN.git", "3.0.4", null, [
|
|
"-DMNN_BUILD_SHARED_LIBS=OFF",
|
|
"-DMNN_AVX512=ON",
|
|
"-DMNN_BUILD_TOOLS=ON",
|
|
"-DMNN_BUILD_CONVERTER=OFF",
|
|
"-DMNN_WIN_RUNTIME_MT=ON",
|
|
], (root) => [
|
|
`set(MNN_INCLUDE_DIR ${JSON.stringify(P(path.join(root, "include")))})`,
|
|
`set(MNN_LIB_DIR ${JSON.stringify(P(path.join(root, "lib")))})`,
|
|
`if(WIN32)`,
|
|
` set(MNN_LIBS \${MNN_LIB_DIR}/MNN.lib)`,
|
|
`else()`,
|
|
` set(MNN_LIBS \${MNN_LIB_DIR}/libMNN.a)`,
|
|
`endif()`,
|
|
].join("\n"));
|
|
//ONNXRuntime
|
|
if (buildOptions.withONNX && !checkFile(THIRDPARTY_DIR, "ONNXRuntime/config.cmake")) {
|
|
let url = "";
|
|
switch (os.platform()) {
|
|
case "win32": {
|
|
switch (os.arch()) {
|
|
case "x64":
|
|
url = "https://huggingface.co/csukuangfj/onnxruntime-libs/resolve/main/onnxruntime-win-x64-static_lib-MinSizeRel-1.20.1.tar.bz2";
|
|
break;
|
|
case "arm64":
|
|
url = "https://huggingface.co/csukuangfj/onnxruntime-libs/resolve/main/onnxruntime-win-arm64-static_lib-1.20.1.tar.bz2";
|
|
break;
|
|
default: assert(false, `不支持的架构${os.arch()}`);
|
|
}
|
|
break;
|
|
}
|
|
case "linux": {
|
|
switch (os.arch()) {
|
|
case "x64":
|
|
url = "https://huggingface.co/csukuangfj/onnxruntime-libs/resolve/main/onnxruntime-linux-x64-static_lib-1.20.1-glibc2_17.zip";
|
|
break;
|
|
case "arm64":
|
|
url = "https://huggingface.co/csukuangfj/onnxruntime-libs/resolve/main/onnxruntime-linux-aarch64-static_lib-1.20.1-glibc2_17.zip";
|
|
break;
|
|
default: assert(false, `不支持的架构${os.arch()}`);
|
|
}
|
|
break;
|
|
}
|
|
case "darwin": {
|
|
switch (os.arch()) {
|
|
case "x64":
|
|
url = "https://huggingface.co/csukuangfj/onnxruntime-libs/resolve/main/onnxruntime-osx-x86_64-static_lib-1.20.1.zip";
|
|
break;
|
|
case "arm64":
|
|
url = "https://huggingface.co/csukuangfj/onnxruntime-libs/resolve/main/onnxruntime-osx-arm64-static_lib-1.20.1.zip";
|
|
break;
|
|
default: assert(false, `不支持的架构${os.arch()}`);
|
|
}
|
|
break;
|
|
}
|
|
default: assert(false, `不支持的平台${os.platform()}`);
|
|
}
|
|
await downloadFromURL("ONNXRuntime", url, (savedir) => {
|
|
const dirname = fs.readdirSync(savedir)[0];
|
|
fs.cpSync(path.join(savedir, dirname), path.join(THIRDPARTY_DIR, "ONNXRuntime"), { recursive: true });
|
|
});
|
|
fs.writeFileSync(path.join(THIRDPARTY_DIR, "ONNXRuntime/config.cmake"), [
|
|
`set(ONNXRuntime_INCLUDE_DIR ${JSON.stringify(P(path.join(THIRDPARTY_DIR, "ONNXRuntime/include")))})`,
|
|
`set(ONNXRuntime_LIB_DIR ${JSON.stringify(P(path.join(THIRDPARTY_DIR, "ONNXRuntime/lib")))})`,
|
|
`if(WIN32)`,
|
|
` set(ONNXRuntime_LIBS \${ONNXRuntime_LIB_DIR}/onnxruntime.lib)`,
|
|
`else()`,
|
|
` set(ONNXRuntime_LIBS \${ONNXRuntime_LIB_DIR}/libonnxruntime.a)`,
|
|
`endif()`,
|
|
].join("\n"));
|
|
}
|
|
// if (buildOptions.withONNX) cmakeBuildFromSource("ONNXRuntime", "https://github.com/csukuangfj/onnxruntime-build.git", "main", (name, repo, branch) => {
|
|
// const sourceDir = downloadSource(name, repo, branch, false, "README.md")
|
|
// if (!checkFile(sourceDir, "onnxruntime/README.md")) {
|
|
// fs.rmSync(path.join(sourceDir, "onnxruntime"), { recursive: true, force: true });
|
|
// downloadSource("ONNXRuntime/onnxruntime", "https://github.com/microsoft/onnxruntime.git", "v1.20.2", true, "README.md")
|
|
// }
|
|
// return sourceDir;
|
|
// }, (sourceDir, buildDir, installDir) => [
|
|
// `-DONNXRUNTIME_SOURCE_DIR=${path.join(sourceDir, "onnxruntime")}`
|
|
// ], (root) => [
|
|
// `set(OnnxRuntime_INCLUDE_DIR ${JSON.stringify(path.join(root, "include"))})`,
|
|
// `set(OnnxRuntime_LIB_DIR ${JSON.stringify(path.join(root, "lib"))})`,
|
|
// `set(OnnxRuntime_LIBS onnxruntime)`,
|
|
// ].join("\n"))
|
|
}
|
|
|
|
main(); |