cpp.js 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/assets/CMakeLists.txt +23 -0
- package/src/bin.js +51 -28
- package/src/functions/createBridge.js +33 -0
- package/src/functions/createWasm.js +95 -0
- package/src/{findOrCreateInterfaceFile.js → functions/findOrCreateInterfaceFile.js} +9 -5
- package/src/index.js +23 -4
- package/src/utils/createTempDir.js +15 -0
- package/src/utils/findCMakeListsFile.js +12 -0
- package/src/utils/getBaseInfo.js +15 -0
- package/src/utils/getCliPath.js +12 -0
- package/src/utils/getConfig.js +140 -0
- package/src/utils/getOsUserAndGroupId.js +10 -0
- package/src/utils/getPathInfo.js +18 -0
- package/assets/CMakeLists.txt +0 -8
- package/src/createBridge.js +0 -28
- package/src/createWasm.js +0 -66
- package/src/findCMakeListsFile.js +0 -17
- package/src/utils.js +0 -101
- /package/src/{extern-post.js → assets/extern-post.js} +0 -0
- /package/src/{createBridge.spec.js → functions/specs/createBridge.spec.js} +0 -0
- /package/src/{findOrCreateInterfaceFile.spec.js → functions/specs/findOrCreateInterfaceFile.spec.js} +0 -0
- /package/src/{pullDockerImage.js → utils/pullDockerImage.js} +0 -0
- /package/src/{findCMakeListsFile.spec.js → utils/specs/findCMakeListsFile.spec.js} +0 -0
- /package/src/{utils.spec.js → utils/specs/utils.spec.js} +0 -0
package/package.json
CHANGED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
cmake_minimum_required(VERSION 3.1)
|
|
2
|
+
project("${PROJECT_NAME}")
|
|
3
|
+
|
|
4
|
+
option(BUILD_BRIDGE "Build Bridge" OFF)
|
|
5
|
+
option(BUILD_SOURCE "Build Source" OFF)
|
|
6
|
+
|
|
7
|
+
if(BUILD_SOURCE)
|
|
8
|
+
file(GLOB BUILD_SRC_FILES "${BASE_DIR}/native/**/*.cpp" "${BASE_DIR}/native/*.cpp" "${BASE_DIR}/src/native/**/*.cpp" "${BASE_DIR}/src/native/*.cpp")
|
|
9
|
+
endif(BUILD_SOURCE)
|
|
10
|
+
unset(BUILD_SOURCE CACHE)
|
|
11
|
+
|
|
12
|
+
message("aa", BUILD_SRC_FILES)
|
|
13
|
+
|
|
14
|
+
if(BUILD_BRIDGE)
|
|
15
|
+
file(GLOB BRIDGE_SRC_FILES "${BRIDGE_DIR}/*.i.cpp")
|
|
16
|
+
endif(BUILD_BRIDGE)
|
|
17
|
+
unset(BUILD_BRIDGE CACHE)
|
|
18
|
+
|
|
19
|
+
set(SRC_FILES "${BUILD_SRC_FILES}" "${BRIDGE_SRC_FILES}")
|
|
20
|
+
add_library("${PROJECT_NAME}" STATIC ${SRC_FILES})
|
|
21
|
+
|
|
22
|
+
file(GLOB HEADERS "${BASE_DIR}/node_modules/cppjs-lib-*/include")
|
|
23
|
+
include_directories("${HEADERS};${BASE_DIR}/native;${BASE_DIR}/src/native")
|
package/src/bin.js
CHANGED
|
@@ -2,38 +2,61 @@
|
|
|
2
2
|
|
|
3
3
|
import packageJSON from '../package.json' assert { type: 'json' };
|
|
4
4
|
import { Command, Argument } from 'commander';
|
|
5
|
+
import fs from 'fs';
|
|
6
|
+
import glob from 'glob';
|
|
7
|
+
import { createDir } from './utils/createTempDir.js';
|
|
5
8
|
|
|
6
|
-
import
|
|
7
|
-
import { createTempDir } from './utils.js';
|
|
9
|
+
import CppjsCompiler from './index.js';
|
|
8
10
|
|
|
9
11
|
const program = new Command();
|
|
10
|
-
program
|
|
11
|
-
.name('cpp.js')
|
|
12
|
-
.description('Compile c++ files to webassembly.')
|
|
13
|
-
.version(packageJSON.version)
|
|
14
|
-
.showHelpAfterError();
|
|
15
12
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
program
|
|
14
|
+
.name('cpp.js')
|
|
15
|
+
.description('Compile c++ files to webassembly.')
|
|
16
|
+
.version(packageJSON.version)
|
|
17
|
+
.showHelpAfterError();
|
|
18
|
+
|
|
19
|
+
const commandGenerate = program.command('generate')
|
|
20
|
+
.description('Generate app or lib.')
|
|
21
|
+
.addArgument(new Argument('<type>', 'Generation type').choices(['app', 'lib']))
|
|
22
|
+
.option('-b, --base <base>', 'base path')
|
|
23
|
+
.option('-p, --platform <platform>', 'platform (wasm)', 'wasm', ['wasm'])
|
|
24
|
+
.option('-o, --output <string>', 'Output path');
|
|
20
25
|
|
|
21
26
|
program.parse(process.argv);
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if (type === '
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
27
|
+
|
|
28
|
+
switch (program.args[0]) {
|
|
29
|
+
case 'generate':
|
|
30
|
+
const type = commandGenerate.args[0];
|
|
31
|
+
const { output, platform, base } = commandGenerate.opts();
|
|
32
|
+
generate(type, platform, output, base);
|
|
33
|
+
break;
|
|
34
|
+
default:
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function generate(type, platform, output, base) {
|
|
39
|
+
if (type === 'lib') generateLib(platform, output, base);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function generateLib(platform, output, base) {
|
|
43
|
+
let headers = [];
|
|
44
|
+
|
|
45
|
+
const compiler = new CppjsCompiler();
|
|
46
|
+
compiler.config.paths.header.forEach(headerPath => {
|
|
47
|
+
headers.push(glob.sync("*.h", { absolute: true, cwd: headerPath }));
|
|
48
|
+
});
|
|
49
|
+
headers = headers.filter(path => !!path.toString()).flat();
|
|
50
|
+
|
|
51
|
+
headers.forEach(header => {
|
|
52
|
+
compiler.findOrCreateInterfaceFile(header);
|
|
53
|
+
compiler.createBridge();
|
|
54
|
+
compiler.createWasm({ cc: ['-O3'] });
|
|
55
|
+
createDir('lib', compiler.config.paths.output);
|
|
56
|
+
fs.copyFileSync(`${compiler.config.paths.temp}/${compiler.config.general.name}.js`, `${compiler.config.paths.output}/${compiler.config.general.name}.js`);
|
|
57
|
+
fs.copyFileSync(`${compiler.config.paths.temp}/${compiler.config.general.name}.wasm`, `${compiler.config.paths.output}/${compiler.config.general.name}.wasm`);
|
|
58
|
+
fs.copyFileSync(`${compiler.config.paths.temp}/lib${compiler.config.general.name}.a`, `${compiler.config.paths.output}/lib/lib${compiler.config.general.name}.a`);
|
|
59
|
+
fs.rmSync(compiler.config.paths.temp, { recursive: true, force: true });
|
|
60
|
+
});
|
|
61
|
+
|
|
39
62
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import glob from 'glob';
|
|
2
|
+
import { execFileSync } from 'child_process';
|
|
3
|
+
import pullDockerImage from '../utils/pullDockerImage.js';
|
|
4
|
+
import getBaseInfo from '../utils/getBaseInfo.js';
|
|
5
|
+
import getPathInfo from '../utils/getPathInfo.js';
|
|
6
|
+
import getOsUserAndGroupId from '../utils/getOsUserAndGroupId.js';
|
|
7
|
+
|
|
8
|
+
export default function createBridge(compiler) {
|
|
9
|
+
pullDockerImage();
|
|
10
|
+
|
|
11
|
+
const bridges = [];
|
|
12
|
+
compiler.interfaces.forEach(filePath => {
|
|
13
|
+
const input = getPathInfo(filePath, compiler.config.paths.base);
|
|
14
|
+
const output = getPathInfo(compiler.config.paths.temp+'/bridge', compiler.config.paths.base);
|
|
15
|
+
const projectPath = getPathInfo(compiler.config.paths.project, compiler.config.paths.base);
|
|
16
|
+
const base = getBaseInfo(compiler.config.paths.base);
|
|
17
|
+
|
|
18
|
+
const includePath = [
|
|
19
|
+
glob.sync("node_modules/cppjs-lib-*-web/include", { absolute: false }),
|
|
20
|
+
glob.sync("native", { absolute: false }),
|
|
21
|
+
glob.sync("src/native", { absolute: false }),
|
|
22
|
+
].filter(path => !!path.toString()).map(path => `-I/live/${projectPath.relative}/${path}`);
|
|
23
|
+
|
|
24
|
+
const options = { cwd: output.absolute, stdio : 'pipe' };
|
|
25
|
+
const args = [
|
|
26
|
+
"run", "--user", getOsUserAndGroupId(), "-v", `${base.withoutSlash}:/live`, "bugra9/cpp.js",
|
|
27
|
+
"swig", "-c++", '-emscripten', '-o', `/live/${output.relative}/${filePath.split('/').at(-1)}.cpp`, ...includePath, `/live/${input.relative}`
|
|
28
|
+
];
|
|
29
|
+
execFileSync("docker", args, options);
|
|
30
|
+
bridges.push(`${base.withSlash}${output.relative}/${filePath.split('/').at(-1)}.cpp`);
|
|
31
|
+
});
|
|
32
|
+
return bridges;
|
|
33
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { execFileSync } from 'child_process';
|
|
2
|
+
import pullDockerImage from '../utils/pullDockerImage.js';
|
|
3
|
+
import getBaseInfo from '../utils/getBaseInfo.js';
|
|
4
|
+
import getPathInfo from '../utils/getPathInfo.js';
|
|
5
|
+
import getOsUserAndGroupId from '../utils/getOsUserAndGroupId.js';
|
|
6
|
+
|
|
7
|
+
export default function createWasm(compiler, options = {}) {
|
|
8
|
+
const compiler2 = new CppjsCompiler(
|
|
9
|
+
compiler.config.paths.cmake,
|
|
10
|
+
compiler.config.paths.output,
|
|
11
|
+
compiler.config.paths.temp,
|
|
12
|
+
compiler.config.paths.cli,
|
|
13
|
+
compiler.config.general.name,
|
|
14
|
+
options,
|
|
15
|
+
compiler.config.paths.base
|
|
16
|
+
);
|
|
17
|
+
return compiler2.compile();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
class CppjsCompiler {
|
|
21
|
+
constructor(cMakeFilePath, outputPath, tempPath, cliPath, name, options = {}, basePath = process.cwd()) {
|
|
22
|
+
this.cMakeFilePath = cMakeFilePath;
|
|
23
|
+
this.outputPath = tempPath;
|
|
24
|
+
this.tempPath = tempPath;
|
|
25
|
+
this.cliPath = cliPath;
|
|
26
|
+
this.options = options;
|
|
27
|
+
this.basePath = basePath;
|
|
28
|
+
this.name = name;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
compile() {
|
|
32
|
+
pullDockerImage();
|
|
33
|
+
|
|
34
|
+
this.cmake(this.name, true, false);
|
|
35
|
+
this.make();
|
|
36
|
+
this.cmake(this.name+'bridge', false, true);
|
|
37
|
+
this.make();
|
|
38
|
+
this.libs = [`lib${this.name}.a`, `lib${this.name}bridge.a`];
|
|
39
|
+
|
|
40
|
+
this.cc();
|
|
41
|
+
|
|
42
|
+
return this.outputPath;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
cmake(name, isBuildSource, isBuildBridge) {
|
|
46
|
+
const params = [];
|
|
47
|
+
if (isBuildSource) params.push('-DBUILD_SOURCE=TRUE');
|
|
48
|
+
if (isBuildBridge) params.push('-DBUILD_BRIDGE=TRUE');
|
|
49
|
+
|
|
50
|
+
const output = getPathInfo(this.outputPath, this.basePath);
|
|
51
|
+
const projectPath = getPathInfo(process.cwd(), this.basePath);
|
|
52
|
+
const base = getBaseInfo(this.basePath);
|
|
53
|
+
|
|
54
|
+
let cMakeParentPath = this.cMakeFilePath.split('/');
|
|
55
|
+
cMakeParentPath.pop();
|
|
56
|
+
cMakeParentPath = cMakeParentPath.join('/');
|
|
57
|
+
const args = [
|
|
58
|
+
"run", "--user", getOsUserAndGroupId(), "-v", `${base.withoutSlash}:/live`, "-v", `${cMakeParentPath}:/cmake`, "--workdir", `/live/${output.relative}`, "bugra9/cpp.js",
|
|
59
|
+
"emcmake", "cmake", "/cmake", `-DBASE_DIR=/live/${projectPath.relative}`,
|
|
60
|
+
`-DCMAKE_INSTALL_PREFIX=/live/${output.relative}`, `-DBRIDGE_DIR=/live/${output.relative}/bridge`, `-DPROJECT_NAME=${name}`, ...params,
|
|
61
|
+
];
|
|
62
|
+
const options = { cwd: this.outputPath, stdio : 'pipe' };
|
|
63
|
+
execFileSync("docker", args, options);
|
|
64
|
+
return this.outputPath;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
make() {
|
|
68
|
+
const output = getPathInfo(this.outputPath, this.basePath);
|
|
69
|
+
const base = getBaseInfo(this.basePath);
|
|
70
|
+
|
|
71
|
+
let cMakeParentPath = this.cMakeFilePath.split('/');
|
|
72
|
+
cMakeParentPath.pop();
|
|
73
|
+
cMakeParentPath = cMakeParentPath.join('/');
|
|
74
|
+
const args = [
|
|
75
|
+
"run", "--user", getOsUserAndGroupId(), "-v", `${base.withoutSlash}:/live`, "-v", `${cMakeParentPath}:/cmake`, "--workdir", `/live/${output.relative}`, "bugra9/cpp.js",
|
|
76
|
+
"emmake", "make"
|
|
77
|
+
];
|
|
78
|
+
const options = { cwd: this.outputPath, stdio : 'pipe' };
|
|
79
|
+
execFileSync("docker", args, options);
|
|
80
|
+
return this.outputPath;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
cc() {
|
|
84
|
+
const input = getPathInfo(this.tempPath, this.basePath);
|
|
85
|
+
const output = getPathInfo(this.outputPath, this.basePath);
|
|
86
|
+
const base = getBaseInfo(this.basePath);
|
|
87
|
+
const args = [
|
|
88
|
+
"run", "--user", getOsUserAndGroupId(), "-v", `${base.withoutSlash}:/live`, "-v", `${this.cliPath}:/cli`, "bugra9/cpp.js",
|
|
89
|
+
"emcc", "-lembind", "-Wl,--whole-archive", ...this.libs.map(lib => `/live/${input.relative}/${lib}`), ...(this.options.cc || []), "-s", "WASM=1", "-s", "MODULARIZE=1", '-o', `/live/${output.relative}/${this.name}.js`, '--extern-post-js', '/cli/assets/extern-post.js'
|
|
90
|
+
];
|
|
91
|
+
const options = { cwd: this.tempPath, stdio : 'pipe' };
|
|
92
|
+
execFileSync("docker", args, options);
|
|
93
|
+
return this.outputPath;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
|
-
import
|
|
2
|
+
import getBaseInfo from '../utils/getBaseInfo.js';
|
|
3
|
+
import getPathInfo from '../utils/getPathInfo.js';
|
|
3
4
|
|
|
4
|
-
export default function findOrCreateInterfaceFile(
|
|
5
|
-
const input = getPathInfo(filePath,
|
|
6
|
-
const output = getPathInfo(
|
|
7
|
-
const base = getBaseInfo(
|
|
5
|
+
export default function findOrCreateInterfaceFile(compiler, filePath) {
|
|
6
|
+
const input = getPathInfo(filePath, compiler.config.paths.base);
|
|
7
|
+
const output = getPathInfo(compiler.config.paths.temp+'/interface', compiler.config.paths.base);
|
|
8
|
+
const base = getBaseInfo(compiler.config.paths.base);
|
|
8
9
|
|
|
9
10
|
const temp = input.relative.match(/^(.*)\..+?$/);
|
|
10
11
|
if (temp.length < 2) return null;
|
|
@@ -33,5 +34,8 @@ export default function findOrCreateInterfaceFile(filePath, outputPath, basePath
|
|
|
33
34
|
`;
|
|
34
35
|
const outputFilePath = base.withSlash + output.relative+'/'+fileName+'.i';
|
|
35
36
|
fs.writeFileSync(outputFilePath, content);
|
|
37
|
+
|
|
38
|
+
compiler.interfaces.push(outputFilePath);
|
|
39
|
+
|
|
36
40
|
return outputFilePath;
|
|
37
41
|
}
|
package/src/index.js
CHANGED
|
@@ -1,4 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import createBridge from './functions/createBridge.js';
|
|
2
|
+
import findOrCreateInterfaceFile from './functions/findOrCreateInterfaceFile.js';
|
|
3
|
+
import createWasm from './functions/createWasm.js';
|
|
4
|
+
import getConfig from './utils/getConfig.js';
|
|
5
|
+
|
|
6
|
+
export default class CppjsCompiler {
|
|
7
|
+
constructor(param) {
|
|
8
|
+
this.config = getConfig(param);
|
|
9
|
+
this.interfaces = [];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
findOrCreateInterfaceFile(path) {
|
|
13
|
+
return findOrCreateInterfaceFile(this, path);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
createBridge() {
|
|
17
|
+
return createBridge(this);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
createWasm(options) {
|
|
21
|
+
return createWasm(this, options);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import p from 'path';
|
|
3
|
+
|
|
4
|
+
export default function createTempDir(folder = 'a'+Math.random(), base = process.cwd()) {
|
|
5
|
+
const path = p.join(base, 'node_modules', ".cppjs");
|
|
6
|
+
return createDir(folder, path);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function createDir(folder, base = process.cwd()) {
|
|
10
|
+
const path = p.join(base, folder);
|
|
11
|
+
|
|
12
|
+
if (fs.existsSync(path)) fs.rmSync(path, { recursive: true, force: true });
|
|
13
|
+
fs.mkdirSync(path, { recursive: true });
|
|
14
|
+
return path;
|
|
15
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import glob from 'glob';
|
|
2
|
+
import getCliPath from './getCliPath.js';
|
|
3
|
+
|
|
4
|
+
export default function findCMakeListsFile(basePath = process.cwd()) {
|
|
5
|
+
let temp = glob.sync("CMakeLists.txt", { absolute: true, cwd: basePath });
|
|
6
|
+
if (temp.length === 0) {
|
|
7
|
+
temp = glob.sync("*/CMakeLists.txt", { absolute: true, cwd: basePath, ignore: ['node_modules/*', 'dist/*', 'build/*'] });
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (temp.length > 0) return temp[0];
|
|
11
|
+
return getCliPath() + '/assets/CMakeLists.txt';
|
|
12
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export default function getBaseInfo(base) {
|
|
2
|
+
let basePath = base;
|
|
3
|
+
|
|
4
|
+
const output = {
|
|
5
|
+
withSlash: '/',
|
|
6
|
+
withoutSlash: '/',
|
|
7
|
+
};
|
|
8
|
+
if (basePath && basePath !== '/') {
|
|
9
|
+
if (basePath.at(-1) !== '/') basePath += '/';
|
|
10
|
+
|
|
11
|
+
output.withSlash = basePath;
|
|
12
|
+
output.withoutSlash = basePath.substring(0, basePath.length - 1);
|
|
13
|
+
}
|
|
14
|
+
return output;
|
|
15
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {dirname} from 'path';
|
|
2
|
+
import * as url from 'node:url';
|
|
3
|
+
|
|
4
|
+
const __filename = url.fileURLToPath(import.meta.url);
|
|
5
|
+
const temp = __filename.split('/');
|
|
6
|
+
temp.pop();
|
|
7
|
+
temp.pop();
|
|
8
|
+
const __dirname = temp.join('/');
|
|
9
|
+
|
|
10
|
+
export default function getCliPath() {
|
|
11
|
+
return __dirname;
|
|
12
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import createTempDir, { createDir } from './createTempDir.js';
|
|
3
|
+
import findCMakeListsFile from './findCMakeListsFile.js';
|
|
4
|
+
import p from 'path';
|
|
5
|
+
import * as url from 'node:url';
|
|
6
|
+
import { createRequire } from 'module';
|
|
7
|
+
|
|
8
|
+
const __filename = url.fileURLToPath(import.meta.url);
|
|
9
|
+
const temp = __filename.split('/'); temp.pop(); temp.pop();
|
|
10
|
+
const __dirname = temp.join('/');
|
|
11
|
+
const require = createRequire(import.meta.url);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @typedef {Object} Config
|
|
15
|
+
* @property {string} general General
|
|
16
|
+
* @property {ConfigPaths} paths Paths
|
|
17
|
+
* @property {ConfigExtensions} extensions Extensions
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @typedef {Object} ConfigPaths
|
|
22
|
+
* @property {string} project Project path.
|
|
23
|
+
* @property {string} base Base path (Use for monorepo structure)
|
|
24
|
+
* @property {string} temp Temp path.
|
|
25
|
+
* @property {string} native Native path (default: ['native', 'src/native']).
|
|
26
|
+
* @property {string} module Module path (default: native path)
|
|
27
|
+
* @property {string} header Header path (default: native path)
|
|
28
|
+
* @property {string} bridge Bridge path (default: native and temp path)
|
|
29
|
+
* @property {string} output Output path (default: 'dist')
|
|
30
|
+
* @property {string} cmake CmakeLists.txt path
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @typedef {Object} ConfigExtensions
|
|
35
|
+
* @property {string} header Header extensions (default: ['h', 'hpp', 'hxx', 'hh'])
|
|
36
|
+
* @property {string} source Source extensions (default: ['c', 'cpp', 'cxx', 'cc'])
|
|
37
|
+
* @property {string} module Module extensions (default: ['i'])
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @typedef {Object} ConfigGeneral
|
|
42
|
+
* @property {string} name Project name
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
export default function getConfig(param) {
|
|
46
|
+
let tempConfig = { general: {}, paths: {}, extensions: {} };
|
|
47
|
+
|
|
48
|
+
if (!param || (typeof param === 'string' || param instanceof String)) {
|
|
49
|
+
const ext = (param || '').split('.').at(-1)
|
|
50
|
+
let filePath;
|
|
51
|
+
|
|
52
|
+
if (param && ['json', 'js', 'mjs', 'cjs', 'ts'].includes(ext)) {
|
|
53
|
+
filePath = `${process.cwd()}/${param}`;
|
|
54
|
+
if (!fs.existsSync(filePath)) filePath = null;
|
|
55
|
+
} else {
|
|
56
|
+
filePath = `${process.cwd()}/.cppjs.config.json`;
|
|
57
|
+
if (!fs.existsSync(filePath)) filePath = null;
|
|
58
|
+
|
|
59
|
+
/* filePath = `${process.cwd()}/.cpp.config.js`;
|
|
60
|
+
if (!fs.existsSync(filePath)) filePath = null; */
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (filePath) {
|
|
64
|
+
const file = require(filePath);
|
|
65
|
+
if (file.default) file = file.default;
|
|
66
|
+
if (typeof file === 'function') tempConfig = file();
|
|
67
|
+
else if (typeof file === "object") tempConfig = file;
|
|
68
|
+
}
|
|
69
|
+
} else if (typeof param === "object") {
|
|
70
|
+
tempConfig = param;
|
|
71
|
+
} else {
|
|
72
|
+
console.error('Error');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return fillConfig(forceToConfigSchema(tempConfig));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function forceToConfigSchema(tempConfig) {
|
|
79
|
+
const config = {
|
|
80
|
+
general: tempConfig && tempConfig.general ? tempConfig.general : {},
|
|
81
|
+
paths: tempConfig && tempConfig.paths ? tempConfig.paths : {},
|
|
82
|
+
extensions: tempConfig && tempConfig.extensions ? tempConfig.extensions : {},
|
|
83
|
+
};
|
|
84
|
+
return config;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function getAbsolutePath(projectPath, path) {
|
|
88
|
+
if (!path) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
if (p.isAbsolute(path)) {
|
|
92
|
+
return path;
|
|
93
|
+
}
|
|
94
|
+
if (projectPath) {
|
|
95
|
+
return p.resolve(p.join(p.resolve(projectPath), path));
|
|
96
|
+
}
|
|
97
|
+
return p.resolve(path);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function fillConfig(tempConfig) {
|
|
101
|
+
const config = {
|
|
102
|
+
general: {},
|
|
103
|
+
paths: {
|
|
104
|
+
project: getAbsolutePath(null, tempConfig.paths.project) || process.cwd(),
|
|
105
|
+
},
|
|
106
|
+
extensions: {},
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
if (!config.general.name) {
|
|
110
|
+
config.general.name = 'cppjssample';
|
|
111
|
+
const packageJsonPath = `${config.paths.project}/package.json`;
|
|
112
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
113
|
+
const file = JSON.parse(fs.readFileSync(packageJsonPath));
|
|
114
|
+
if (file && typeof file === 'object' && file.name){
|
|
115
|
+
config.general.name = file.name;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const getPath = getAbsolutePath.bind(null, config.paths.project);
|
|
121
|
+
|
|
122
|
+
config.paths.base = getPath(tempConfig.paths.base) || config.paths.project;
|
|
123
|
+
config.paths.temp = getPath(tempConfig.paths.temp) || createTempDir(undefined, config.paths.project)
|
|
124
|
+
config.paths.native = (tempConfig.paths.native || ['native', 'src/native']).map(p => getPath(p));
|
|
125
|
+
config.paths.module = (tempConfig.paths.module || config.paths.native).map(p => getPath(p));
|
|
126
|
+
config.paths.header = (tempConfig.paths.header || config.paths.native).map(p => getPath(p));
|
|
127
|
+
config.paths.bridge = (tempConfig.paths.bridge || [...config.paths.native, config.paths.temp]).map(p => getPath(p));
|
|
128
|
+
config.paths.output = getPath(tempConfig.paths.output) || config.paths.temp;
|
|
129
|
+
config.paths.cmake = getPath(tempConfig.paths.cmake || findCMakeListsFile(config.paths.project));
|
|
130
|
+
config.paths.cli = __dirname;
|
|
131
|
+
|
|
132
|
+
config.extensions.header = tempConfig.extensions.header || ['h', 'hpp', 'hxx', 'hh'];
|
|
133
|
+
config.extensions.source = tempConfig.extensions.source || ['c', 'cpp', 'cxx', 'cc'];
|
|
134
|
+
config.extensions.module = tempConfig.extensions.module || ['i'];
|
|
135
|
+
|
|
136
|
+
createDir('interface', config.paths.temp);
|
|
137
|
+
createDir('bridge', config.paths.temp);
|
|
138
|
+
|
|
139
|
+
return config;
|
|
140
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export default function getPathInfo(path, base) {
|
|
2
|
+
let basePath = base;
|
|
3
|
+
|
|
4
|
+
const output = {
|
|
5
|
+
relative: path,
|
|
6
|
+
absolute: path,
|
|
7
|
+
};
|
|
8
|
+
if (basePath) {
|
|
9
|
+
if (basePath.at(-1) !== '/') basePath += '/';
|
|
10
|
+
|
|
11
|
+
if (path.substring(0, basePath.length) === basePath) {
|
|
12
|
+
output.relative = path.substring(basePath.length);
|
|
13
|
+
} else {
|
|
14
|
+
output.absolute = basePath + path;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return output;
|
|
18
|
+
}
|
package/assets/CMakeLists.txt
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
cmake_minimum_required(VERSION 3.1)
|
|
2
|
-
project(cppjs)
|
|
3
|
-
|
|
4
|
-
file(GLOB SRC_FILES "${BASE_DIR}/native/**/*.cpp" "${BASE_DIR}/native/*.cpp" "${BASE_DIR}/src/native/**/*.cpp" "${BASE_DIR}/src/native/*.cpp" "${BRIDGE_DIR}/*.i.cpp")
|
|
5
|
-
add_library(cppjs STATIC ${SRC_FILES})
|
|
6
|
-
|
|
7
|
-
file(GLOB HEADERS "${BASE_DIR}/node_modules/cppjs-lib-*/include")
|
|
8
|
-
include_directories("${HEADERS};${BASE_DIR}/native;${BASE_DIR}/src/native")
|
package/src/createBridge.js
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import glob from 'glob';
|
|
2
|
-
import os from "os";
|
|
3
|
-
import { execFileSync } from 'child_process';
|
|
4
|
-
import pullDockerImage from './pullDockerImage.js';
|
|
5
|
-
import { getBaseInfo, getPathInfo, getOsUserAndGroupId } from './utils.js';
|
|
6
|
-
|
|
7
|
-
export default function createBridge(filePath, outputPath, basePath = process.cwd()) {
|
|
8
|
-
pullDockerImage();
|
|
9
|
-
|
|
10
|
-
const input = getPathInfo(filePath, basePath);
|
|
11
|
-
const output = getPathInfo(outputPath, basePath);
|
|
12
|
-
const projectPath = getPathInfo(process.cwd(), basePath);
|
|
13
|
-
const base = getBaseInfo(basePath);
|
|
14
|
-
|
|
15
|
-
const includePath = [
|
|
16
|
-
glob.sync("node_modules/cppjs-lib-*-web/include", { absolute: false }),
|
|
17
|
-
glob.sync("native", { absolute: false }),
|
|
18
|
-
glob.sync("src/native", { absolute: false }),
|
|
19
|
-
].filter(path => !!path.toString()).map(path => `-I/live/${projectPath.relative}/${path}`);
|
|
20
|
-
|
|
21
|
-
const options = { cwd: outputPath, stdio : 'pipe' };
|
|
22
|
-
const args = [
|
|
23
|
-
"run", "--user", getOsUserAndGroupId(), "-v", `${base.withoutSlash}:/live`, "bugra9/cpp.js",
|
|
24
|
-
"swig", "-c++", '-emscripten', '-o', `/live/${output.relative}/${filePath.split('/').at(-1)}.cpp`, ...includePath, `/live/${input.relative}`
|
|
25
|
-
];
|
|
26
|
-
execFileSync("docker", args, options);
|
|
27
|
-
return `${base.withSlash}${output.relative}/${filePath.split('/').at(-1)}.cpp`;
|
|
28
|
-
}
|
package/src/createWasm.js
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { execFileSync } from 'child_process';
|
|
2
|
-
import * as url from 'node:url';
|
|
3
|
-
import pullDockerImage from './pullDockerImage.js';
|
|
4
|
-
import { getBaseInfo, getPathInfo, getOsUserAndGroupId } from './utils.js';
|
|
5
|
-
|
|
6
|
-
const __filename = url.fileURLToPath(import.meta.url);
|
|
7
|
-
const temp = __filename.split('/');
|
|
8
|
-
temp.pop();
|
|
9
|
-
temp.pop();
|
|
10
|
-
const __dirname = temp.join('/');
|
|
11
|
-
|
|
12
|
-
export default function createWasm(cMakeFilePath, outputPath, tempPath, options = {}, basePath = process.cwd()) {
|
|
13
|
-
pullDockerImage();
|
|
14
|
-
cmake(cMakeFilePath, tempPath, basePath);
|
|
15
|
-
make(cMakeFilePath, tempPath, basePath);
|
|
16
|
-
cc(tempPath, outputPath, options.cc, basePath);
|
|
17
|
-
|
|
18
|
-
return outputPath;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function cmake(cMakeFilePath, outputPath, basePath) {
|
|
22
|
-
const output = getPathInfo(outputPath, basePath);
|
|
23
|
-
const projectPath = getPathInfo(process.cwd(), basePath);
|
|
24
|
-
const base = getBaseInfo(basePath);
|
|
25
|
-
|
|
26
|
-
let cMakeParentPath = cMakeFilePath.split('/');
|
|
27
|
-
cMakeParentPath.pop();
|
|
28
|
-
cMakeParentPath = cMakeParentPath.join('/');
|
|
29
|
-
const args = [
|
|
30
|
-
"run", "--user", getOsUserAndGroupId(), "-v", `${base.withoutSlash}:/live`, "-v", `${cMakeParentPath}:/cmake`, "--workdir", `/live/${output.relative}`, "bugra9/cpp.js",
|
|
31
|
-
"emcmake", "cmake", "/cmake", `-DBASE_DIR=/live/${projectPath.relative}`,
|
|
32
|
-
`-DCMAKE_INSTALL_PREFIX=/live/${output.relative}`, `-DBRIDGE_DIR=/live/${output.relative}`,
|
|
33
|
-
];
|
|
34
|
-
const options = { cwd: outputPath, stdio : 'pipe' };
|
|
35
|
-
execFileSync("docker", args, options);
|
|
36
|
-
return outputPath;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function make(cMakeFilePath, outputPath, basePath) {
|
|
40
|
-
const output = getPathInfo(outputPath, basePath);
|
|
41
|
-
const base = getBaseInfo(basePath);
|
|
42
|
-
|
|
43
|
-
let cMakeParentPath = cMakeFilePath.split('/');
|
|
44
|
-
cMakeParentPath.pop();
|
|
45
|
-
cMakeParentPath = cMakeParentPath.join('/');
|
|
46
|
-
const args = [
|
|
47
|
-
"run", "--user", getOsUserAndGroupId(), "-v", `${base.withoutSlash}:/live`, "-v", `${cMakeParentPath}:/cmake`, "--workdir", `/live/${output.relative}`, "bugra9/cpp.js",
|
|
48
|
-
"emmake", "make"
|
|
49
|
-
];
|
|
50
|
-
const options = { cwd: outputPath, stdio : 'pipe' };
|
|
51
|
-
execFileSync("docker", args, options);
|
|
52
|
-
return outputPath;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function cc(tempPath, outputPath, flags = [], basePath) {
|
|
56
|
-
const input = getPathInfo(tempPath, basePath);
|
|
57
|
-
const output = getPathInfo(outputPath, basePath);
|
|
58
|
-
const base = getBaseInfo(basePath);
|
|
59
|
-
const args = [
|
|
60
|
-
"run", "--user", getOsUserAndGroupId(), "-v", `${base.withoutSlash}:/live`, "-v", `${__dirname}:/cli`, "bugra9/cpp.js",
|
|
61
|
-
"emcc", "-lembind", "-Wl,--whole-archive", `/live/${input.relative}/libcppjs.a`, ...flags, "-s", "WASM=1", "-s", "MODULARIZE=1", '-o', `/live/${output.relative}/cpp.js`, '--extern-post-js', '/cli/src/extern-post.js'
|
|
62
|
-
];
|
|
63
|
-
const options = { cwd: tempPath, stdio : 'pipe' };
|
|
64
|
-
execFileSync("docker", args, options);
|
|
65
|
-
return outputPath;
|
|
66
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import glob from 'glob';
|
|
3
|
-
import {dirname} from 'path';
|
|
4
|
-
import * as url from 'node:url';
|
|
5
|
-
|
|
6
|
-
export const __filename = url.fileURLToPath(import.meta.url);
|
|
7
|
-
export const __dirname = dirname(dirname(__filename)+'..');
|
|
8
|
-
|
|
9
|
-
export default function findCMakeListsFile() {
|
|
10
|
-
let temp = glob.sync("CMakeLists.txt", { absolute: true });
|
|
11
|
-
if (temp.length === 0) {
|
|
12
|
-
temp = glob.sync("*/CMakeLists.txt", { absolute: true, ignore: ['node_modules/*', 'dist/*', 'build/*'] });
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
if (temp.length > 0) return temp[0];
|
|
16
|
-
return __dirname + '/assets/CMakeLists.txt';
|
|
17
|
-
}
|
package/src/utils.js
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import p, {dirname} from 'path';
|
|
3
|
-
import os, { tmpdir } from "os";
|
|
4
|
-
import * as url from 'node:url';
|
|
5
|
-
|
|
6
|
-
export const __filename = url.fileURLToPath(import.meta.url);
|
|
7
|
-
export const __dirname = dirname(__filename);
|
|
8
|
-
|
|
9
|
-
let config;
|
|
10
|
-
export const mainPath = process.cwd();
|
|
11
|
-
|
|
12
|
-
export function createTempDir(folder) {
|
|
13
|
-
let path = p.join(tmpdir(), "cppjs-app-cli");
|
|
14
|
-
if (folder) path = p.join(path, folder);
|
|
15
|
-
|
|
16
|
-
if (fs.existsSync(path)) fs.rmdirSync(path);
|
|
17
|
-
fs.mkdirSync(path, { recursive: true });
|
|
18
|
-
|
|
19
|
-
return path;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function getFilesGivenDir(dir, options = {}) {
|
|
23
|
-
return new Promise((resolve, reject) => {
|
|
24
|
-
fs.readdir(dir, (err, files) => {
|
|
25
|
-
if (err) reject(err);
|
|
26
|
-
|
|
27
|
-
let filteredFiles = files;
|
|
28
|
-
if (options.ext && Array.isArray(options.ext) && options.ext.length > 0) {
|
|
29
|
-
const regex = new RegExp(`\.(${options.ext.join('|')})$`, 'g');
|
|
30
|
-
filteredFiles = filteredFiles.filter(file => regex.test(file));
|
|
31
|
-
}
|
|
32
|
-
if (options.filter) filteredFiles = filteredFiles.filter(options.filter);
|
|
33
|
-
resolve(filteredFiles);
|
|
34
|
-
});
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export async function getConfig(projectPath) {
|
|
39
|
-
if (config) return config;
|
|
40
|
-
if (!projectPath) projectPath = mainPath;
|
|
41
|
-
|
|
42
|
-
config = {
|
|
43
|
-
projectPath,
|
|
44
|
-
modulesPath: projectPath,
|
|
45
|
-
modulesTempPath: createTempDir('modules'),
|
|
46
|
-
bridgesTempPath: createTempDir('bridges'),
|
|
47
|
-
output: `${projectPath}/dist`,
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
const configFilePath = `${projectPath}/.cppjs.config.js`;
|
|
51
|
-
if (fs.existsSync(configFilePath)) {
|
|
52
|
-
config = Object.assign({}, config, (await import(configFilePath)).default);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return config;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
let osUserAndGroupId;
|
|
59
|
-
export function getOsUserAndGroupId() {
|
|
60
|
-
const userInfo = os.userInfo();
|
|
61
|
-
if (!osUserAndGroupId) {
|
|
62
|
-
osUserAndGroupId = `${userInfo.uid}:${userInfo.gid}`;
|
|
63
|
-
}
|
|
64
|
-
return osUserAndGroupId;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export function getBaseInfo(base) {
|
|
68
|
-
let basePath = base;
|
|
69
|
-
|
|
70
|
-
const output = {
|
|
71
|
-
withSlash: '/',
|
|
72
|
-
withoutSlash: '/',
|
|
73
|
-
};
|
|
74
|
-
if (basePath && basePath !== '/') {
|
|
75
|
-
if (basePath.at(-1) !== '/') basePath += '/';
|
|
76
|
-
|
|
77
|
-
output.withSlash = basePath;
|
|
78
|
-
output.withoutSlash = basePath.substring(0, basePath.length - 1);
|
|
79
|
-
}
|
|
80
|
-
return output;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
export function getPathInfo(path, base) {
|
|
85
|
-
let basePath = base;
|
|
86
|
-
|
|
87
|
-
const output = {
|
|
88
|
-
relative: path,
|
|
89
|
-
absolute: path,
|
|
90
|
-
};
|
|
91
|
-
if (basePath) {
|
|
92
|
-
if (basePath.at(-1) !== '/') basePath += '/';
|
|
93
|
-
|
|
94
|
-
if (path.substring(0, basePath.length) === basePath) {
|
|
95
|
-
output.relative = path.substring(basePath.length);
|
|
96
|
-
} else {
|
|
97
|
-
output.absolute = basePath + path;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
return output;
|
|
101
|
-
}
|
|
File without changes
|
|
File without changes
|
/package/src/{findOrCreateInterfaceFile.spec.js → functions/specs/findOrCreateInterfaceFile.spec.js}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|