cpp.js 1.0.0-beta.7 → 1.0.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/CHANGELOG.md +13 -0
- package/LICENSE +1 -1
- package/README.md +9 -26
- package/package.json +23 -23
- package/src/{functions/buildJS.js → actions/buildJs.js} +7 -6
- package/src/actions/buildWasm.js +68 -0
- package/src/actions/createInterface.js +128 -0
- package/src/actions/createLib.js +104 -0
- package/src/actions/createXCFramework.js +44 -0
- package/src/actions/getAllBridges.js +8 -0
- package/src/actions/getCmakeParameters.js +56 -0
- package/src/actions/getData.js +28 -0
- package/src/actions/getDependLibs.js +19 -0
- package/src/{functions → actions}/run.js +118 -64
- package/src/assets/CMakeLists.txt +14 -10
- package/src/assets/commonBridges.cpp +16 -0
- package/src/assets/dist.cmake +1 -1
- package/src/assets/ios.toolchain.cmake +4 -4
- package/src/bin.js +255 -96
- package/src/index.js +13 -63
- package/src/integration/getCppJsScript.js +91 -0
- package/src/integration/getDependFilePath.js +34 -0
- package/src/state/calculateDependencyParameters.js +64 -0
- package/src/state/index.js +81 -0
- package/src/state/loadConfig.js +104 -0
- package/src/utils/downloadAndExtractFile.js +36 -0
- package/src/utils/findFiles.js +5 -0
- package/src/utils/fixPackageName.js +7 -0
- package/src/utils/getAbsolutePath.js +14 -0
- package/src/utils/getCMakeListsFilePath.js +17 -0
- package/src/utils/getOsUserAndGroupId.js +1 -1
- package/src/utils/getParentPath.js +12 -0
- package/src/utils/hash.js +20 -0
- package/src/utils/loadJs.js +32 -0
- package/src/utils/loadJson.js +16 -0
- package/src/utils/pullDockerImage.js +2 -2
- package/src/utils/systemKeys.js +18 -0
- package/src/utils/writeJson.js +9 -0
- package/.mocharc.yaml +0 -3
- package/src/functions/createBridge.js +0 -37
- package/src/functions/createLib.js +0 -44
- package/src/functions/createWasm.js +0 -67
- package/src/functions/findOrCreateInterfaceFile.js +0 -68
- package/src/functions/finishBuild.js +0 -43
- package/src/functions/getCmakeParams.js +0 -106
- package/src/functions/getData.js +0 -36
- package/src/functions/getLibs.js +0 -33
- package/src/functions/specs/createBridge.spec.js +0 -51
- package/src/functions/specs/findOrCreateInterfaceFile.spec.js +0 -49
- package/src/utils/createTempDir.js +0 -15
- package/src/utils/findCMakeListsFile.js +0 -16
- package/src/utils/getBaseInfo.js +0 -15
- package/src/utils/getCliPath.js +0 -12
- package/src/utils/getConfig.js +0 -170
- package/src/utils/getDirName.js +0 -8
- package/src/utils/getPathInfo.js +0 -10
- package/src/utils/specs/findCMakeListsFile.spec.js +0 -34
- package/src/utils/specs/utils.spec.js +0 -81
- package/test/data/sample.cpp +0 -1
- package/test/data/sample.h +0 -10
- package/test/data/sample.i +0 -12
- package/test/data/sample2.ei +0 -12
- package/test/data/sample2.h +0 -10
- /package/{test/data/sample2.cpp → src/assets/cppjsEmptySource.cpp} +0 -0
package/CHANGELOG.md
ADDED
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -14,6 +14,11 @@
|
|
|
14
14
|
<a href="https://github.com/bugra9/cpp.js/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/github/license/bugra9/cpp.js?style=for-the-badge" /></a>
|
|
15
15
|
<a href="https://github.com/bugra9/cpp.js/discussions"><img alt="Discussions" src="https://img.shields.io/github/discussions/bugra9/cpp.js?style=for-the-badge" /></a>
|
|
16
16
|
<a href="https://github.com/bugra9/cpp.js/issues"><img alt="Issues" src="https://img.shields.io/github/issues/bugra9/cpp.js?style=for-the-badge" /></a>
|
|
17
|
+
<br />
|
|
18
|
+
<img alt="CodeQL" src="https://img.shields.io/github/actions/workflow/status/bugra9/cpp.js/github-code-scanning/codeql?branch=main&style=for-the-badge&label=CodeQL">
|
|
19
|
+
<img alt="Linux Build" src="https://img.shields.io/github/actions/workflow/status/bugra9/cpp.js/build-linux.yml?branch=main&style=for-the-badge&label=Linux%20Build">
|
|
20
|
+
<img alt="Macos Build" src="https://img.shields.io/github/actions/workflow/status/bugra9/cpp.js/build-macos.yml?branch=main&style=for-the-badge&label=Macos%20Build">
|
|
21
|
+
<img alt="Windows Build" src="https://img.shields.io/github/actions/workflow/status/bugra9/cpp.js/build-windows.yml?branch=main&style=for-the-badge&label=Windows%20Build">
|
|
17
22
|
</div>
|
|
18
23
|
|
|
19
24
|
<h3 align="center">
|
|
@@ -23,15 +28,15 @@
|
|
|
23
28
|
<span> · </span>
|
|
24
29
|
<a href="https://cpp.js.org/docs/api/cpp-bindings/overview">C++ Bindings</a>
|
|
25
30
|
<span> · </span>
|
|
26
|
-
<a href="https://cpp.js.org/showcase">Showcase</a>
|
|
31
|
+
<a href="https://cpp.js.org/docs/package/package/showcase">Showcase</a>
|
|
27
32
|
</h3>
|
|
28
33
|
|
|
29
34
|
## Basic Usage
|
|
30
35
|
**src/index.js**
|
|
31
36
|
```js
|
|
32
|
-
import { initCppJs } from './native/Factorial.h';
|
|
37
|
+
import { initCppJs, Factorial } from './native/Factorial.h';
|
|
33
38
|
|
|
34
|
-
|
|
39
|
+
await initCppJs();
|
|
35
40
|
const factorial = new Factorial(99999);
|
|
36
41
|
const result = factorial.calculate();
|
|
37
42
|
console.log(result);
|
|
@@ -72,30 +77,8 @@ To set up a new cpp.js project with a minimal starter structure, execute the fol
|
|
|
72
77
|
```sh
|
|
73
78
|
npm create cpp.js@latest
|
|
74
79
|
```
|
|
75
|
-
## Integrate Into Existing Project
|
|
76
|
-
Integrate cpp.js seamlessly into your existing projects using the appropriate packages for your development needs. Refer to the documentation links for detailed integration guides.
|
|
77
|
-
|
|
78
|
-
| Platform | Package(s) | Documentation |
|
|
79
|
-
| -------- | ---------- | ------------- |
|
|
80
|
-
| Standalone | [cpp.js](https://www.npmjs.com/package/cpp.js) | [Learn](https://cpp.js.org/docs/guide/integrate-into-existing-project/standalone) |
|
|
81
|
-
| Webpack | [cppjs-webpack-plugin](https://www.npmjs.com/package/cppjs-webpack-plugin), [cppjs-loader](https://www.npmjs.com/package/cppjs-loader) | [Learn](https://cpp.js.org/docs/guide/integrate-into-existing-project/webpack) |
|
|
82
|
-
| Rollup | [rollup-plugin-cppjs](https://www.npmjs.com/package/rollup-plugin-cppjs) | [Learn](https://cpp.js.org/docs/guide/integrate-into-existing-project/rollup) |
|
|
83
|
-
| Vite | [vite-plugin-cppjs](https://www.npmjs.com/package/vite-plugin-cppjs) | [Learn](https://cpp.js.org/docs/guide/integrate-into-existing-project/vite) |
|
|
84
|
-
| Rspack | [cppjs-webpack-plugin](https://www.npmjs.com/package/cppjs-webpack-plugin), [cppjs-loader](https://www.npmjs.com/package/cppjs-loader) | [Learn](https://cpp.js.org/docs/guide/integrate-into-existing-project/rspack) |
|
|
85
|
-
| Create React App (CRA) | [cppjs-webpack-plugin](https://www.npmjs.com/package/cppjs-webpack-plugin), [cppjs-loader](https://www.npmjs.com/package/cppjs-loader) | [Learn](https://cpp.js.org/docs/guide/integrate-into-existing-project/create-react-app) |
|
|
86
|
-
| React Native | [cppjs-plugin-react-native](https://www.npmjs.com/package/cppjs-plugin-react-native), [cppjs-plugin-react-native-ios-helper](https://www.npmjs.com/package/cppjs-plugin-react-native-ios-helper), [cppjs-core-rn-embind](https://www.npmjs.com/package/cppjs-core-rn-embind) | [Learn](https://cpp.js.org/docs/guide/integrate-into-existing-project/react-native) |
|
|
87
|
-
| Expo | [cppjs-plugin-react-native](https://www.npmjs.com/package/cppjs-plugin-react-native), [cppjs-plugin-react-native-ios-helper](https://www.npmjs.com/package/cppjs-plugin-react-native-ios-helper), [cppjs-core-rn-embind](https://www.npmjs.com/package/cppjs-core-rn-embind) | [Learn](https://cpp.js.org/docs/guide/integrate-into-existing-project/expo) |
|
|
88
|
-
| Node.js | [cpp.js](https://www.npmjs.com/package/cpp.js) | [Learn](https://cpp.js.org/docs/guide/integrate-into-existing-project/nodejs) |
|
|
89
|
-
| Cloudflare Workers | [cpp.js](https://www.npmjs.com/package/cpp.js) | [Learn](https://cpp.js.org/docs/guide/integrate-into-existing-project/cloudflare-worker) |
|
|
90
|
-
|
|
91
|
-
## Features
|
|
92
|
-
- [Calling C++ from JavaScript](https://cpp.js.org/docs/guide/features/calling-cpp-from-javascript)
|
|
93
|
-
- [Packages](https://cpp.js.org/docs/guide/features/packages)
|
|
94
|
-
- [Plugins](https://cpp.js.org/docs/guide/features/plugins)
|
|
95
|
-
- [Assets](https://cpp.js.org/docs/guide/features/assets)
|
|
96
|
-
- [Working with a Monorepo](https://cpp.js.org/docs/guide/features/monorepo)
|
|
97
80
|
|
|
98
81
|
## License
|
|
99
82
|
[MIT](https://github.com/bugra9/cpp.js/blob/main/LICENSE)
|
|
100
83
|
|
|
101
|
-
Copyright (c)
|
|
84
|
+
Copyright (c) 2025, Buğra Sarı
|
package/package.json
CHANGED
|
@@ -1,39 +1,39 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cpp.js",
|
|
3
|
-
"version": "1.0.0
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"license": "MIT",
|
|
5
|
-
"type": "module",
|
|
6
5
|
"homepage": "https://cpp.js.org",
|
|
7
6
|
"repository": "https://github.com/bugra9/cpp.js.git",
|
|
8
7
|
"description": "Bind C++ to JavaScript without extra code. Cpp.js supports WebAssembly and React Native for cross-platform compatibility.",
|
|
9
|
-
"
|
|
10
|
-
"WebAssembly",
|
|
11
|
-
"React Native",
|
|
12
|
-
"bind",
|
|
13
|
-
"c++",
|
|
14
|
-
"emscripten",
|
|
15
|
-
"embind",
|
|
16
|
-
"swig"
|
|
17
|
-
],
|
|
8
|
+
"type": "module",
|
|
18
9
|
"bin": {
|
|
19
10
|
"cpp.js": "./src/bin.js",
|
|
20
11
|
"cppjs": "./src/bin.js"
|
|
21
12
|
},
|
|
22
13
|
"main": "src/index.js",
|
|
23
14
|
"dependencies": {
|
|
24
|
-
"@rollup/plugin-commonjs": "^
|
|
25
|
-
"@rollup/plugin-
|
|
15
|
+
"@rollup/plugin-commonjs": "^28.0.2",
|
|
16
|
+
"@rollup/plugin-json": "^6.1.0",
|
|
17
|
+
"@rollup/plugin-node-resolve": "^16.0.0",
|
|
26
18
|
"@rollup/plugin-virtual": "^3.0.2",
|
|
27
19
|
"commander": "^12.1.0",
|
|
28
|
-
"glob": "^
|
|
29
|
-
"rollup": "^4.
|
|
30
|
-
"
|
|
31
|
-
"
|
|
20
|
+
"glob": "^11.0.0",
|
|
21
|
+
"rollup": "^4.29.1",
|
|
22
|
+
"upath": "^2.0.1",
|
|
23
|
+
"decompress": "^4.2.1",
|
|
24
|
+
"follow-redirects": "^1.15.9",
|
|
25
|
+
"replace": "^1.2.2"
|
|
32
26
|
},
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
"
|
|
38
|
-
|
|
27
|
+
"keywords": [
|
|
28
|
+
"webassembly",
|
|
29
|
+
"react-native",
|
|
30
|
+
"bind",
|
|
31
|
+
"c++",
|
|
32
|
+
"emscripten",
|
|
33
|
+
"embind",
|
|
34
|
+
"swig",
|
|
35
|
+
"android",
|
|
36
|
+
"ios",
|
|
37
|
+
"mobile"
|
|
38
|
+
]
|
|
39
39
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/* eslint-disable no-await-in-loop */
|
|
2
2
|
/* eslint-disable no-restricted-syntax */
|
|
3
|
-
import fs from 'fs';
|
|
4
3
|
import { rollup } from 'rollup';
|
|
5
4
|
import { nodeResolve } from '@rollup/plugin-node-resolve';
|
|
6
5
|
import commonjs from '@rollup/plugin-commonjs';
|
|
7
6
|
import virtual from '@rollup/plugin-virtual';
|
|
7
|
+
import state from '../state/index.js';
|
|
8
|
+
import getData from './getData.js';
|
|
8
9
|
|
|
9
10
|
const nodeLibs = {
|
|
10
11
|
fs: 'export default {};',
|
|
@@ -34,14 +35,14 @@ const options = {
|
|
|
34
35
|
},
|
|
35
36
|
};
|
|
36
37
|
|
|
37
|
-
export default async function buildJS(
|
|
38
|
-
const entryJS = `${
|
|
39
|
-
const env = JSON.stringify(
|
|
38
|
+
export default async function buildJS(input, type) {
|
|
39
|
+
const entryJS = `${state.config.paths.cli}/assets/${type}.js`;
|
|
40
|
+
const env = JSON.stringify(getData('env', 'Emscripten-x86_64', type));
|
|
40
41
|
const systemConfig = `export default {
|
|
41
42
|
env: ${env},
|
|
42
43
|
paths: {
|
|
43
|
-
wasm: '${
|
|
44
|
-
data: '${
|
|
44
|
+
wasm: '${state.config.general.name}.wasm',
|
|
45
|
+
data: '${state.config.general.name}.data.txt'
|
|
45
46
|
}
|
|
46
47
|
}`;
|
|
47
48
|
let file = input;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import run from './run.js';
|
|
3
|
+
import getDependLibs from './getDependLibs.js';
|
|
4
|
+
import getData from './getData.js';
|
|
5
|
+
import buildJs from './buildJs.js';
|
|
6
|
+
import state from '../state/index.js';
|
|
7
|
+
|
|
8
|
+
export default async function buildWasm(type, isProd = false) {
|
|
9
|
+
const buildType = isProd ? 'Release' : 'Debug';
|
|
10
|
+
const libs = [
|
|
11
|
+
...getDependLibs(),
|
|
12
|
+
`${state.config.paths.build}/Source-${buildType}/Emscripten-x86_64/lib${state.config.general.name}.a`,
|
|
13
|
+
`${state.config.paths.build}/Bridge-${buildType}/Emscripten-x86_64/lib${state.config.general.name}.a`,
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
if (type === 'browser') {
|
|
17
|
+
console.log('wasm compiling for browser...');
|
|
18
|
+
const t0 = performance.now();
|
|
19
|
+
const data = Object.entries(getData('data', 'Emscripten-x86_64', 'browser')).map(([key, value]) => ['--preload-file', `${key.replaceAll('@', '@@')}@${value}`]).flat();
|
|
20
|
+
run('emcc', [
|
|
21
|
+
'-lembind', '-Wl,--whole-archive',
|
|
22
|
+
...libs, ...(isProd ? ['-O3'] : []),
|
|
23
|
+
'-s', 'WASM=1', '-s', 'MODULARIZE=1', '-s', 'DYNAMIC_EXECUTION=0',
|
|
24
|
+
'-s', 'RESERVED_FUNCTION_POINTERS=200', '-s', 'DISABLE_EXCEPTION_CATCHING=0', '-s', 'FORCE_FILESYSTEM=1',
|
|
25
|
+
'-s', 'ALLOW_MEMORY_GROWTH=1',
|
|
26
|
+
'-s', 'EXPORTED_RUNTIME_METHODS=["FS", "ENV"]',
|
|
27
|
+
'-o', `${state.config.paths.build}/${state.config.general.name}.js`,
|
|
28
|
+
...data,
|
|
29
|
+
]);
|
|
30
|
+
const t1 = performance.now();
|
|
31
|
+
console.log('wasm compiled for browser...', Math.round(t1 - t0));
|
|
32
|
+
console.log('js compiling for browser...');
|
|
33
|
+
await buildJs(`${state.config.paths.build}/${state.config.general.name}.js`, 'browser');
|
|
34
|
+
const t2 = performance.now();
|
|
35
|
+
console.log('js compiled for browser...', Math.round(t2 - t1));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (type === 'node') {
|
|
39
|
+
console.log('wasm compiling for node...');
|
|
40
|
+
run('emcc', [
|
|
41
|
+
'-lembind', '-Wl,--whole-archive', '-lnodefs.js',
|
|
42
|
+
...libs, ...(isProd ? ['-O3'] : []),
|
|
43
|
+
'-s', 'WASM=1', '-s', 'MODULARIZE=1', '-s', 'DYNAMIC_EXECUTION=0',
|
|
44
|
+
'-s', 'RESERVED_FUNCTION_POINTERS=200', '-s', 'DISABLE_EXCEPTION_CATCHING=0', '-s', 'FORCE_FILESYSTEM=1', '-s', 'NODERAWFS',
|
|
45
|
+
'-s', 'ALLOW_MEMORY_GROWTH=1',
|
|
46
|
+
'-s', 'EXPORTED_RUNTIME_METHODS=["FS", "ENV", "NODEFS"]',
|
|
47
|
+
'-o', `${state.config.paths.build}/${state.config.general.name}.js`,
|
|
48
|
+
]);
|
|
49
|
+
console.log('wasm compiled for node...');
|
|
50
|
+
console.log('js compiling for node...');
|
|
51
|
+
await buildJs(`${state.config.paths.build}/${state.config.general.name}.js`, 'node');
|
|
52
|
+
console.log('js compiled for node...');
|
|
53
|
+
|
|
54
|
+
Object.entries(getData('data', 'Emscripten-x86_64', 'node')).forEach(([key, value]) => {
|
|
55
|
+
if (fs.existsSync(key)) {
|
|
56
|
+
const dAssetPath = `${state.config.paths.build}/data/${value}`;
|
|
57
|
+
if (!fs.existsSync(dAssetPath)) {
|
|
58
|
+
fs.mkdirSync(dAssetPath, { recursive: true });
|
|
59
|
+
fs.cpSync(key, dAssetPath, { recursive: true });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (fs.existsSync(`${state.config.paths.build}/${state.config.general.name}.data`)) {
|
|
66
|
+
fs.renameSync(`${state.config.paths.build}/${state.config.general.name}.data`, `${state.config.paths.build}/${state.config.general.name}.data.txt`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/* eslint-disable prefer-destructuring */
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import upath from 'upath';
|
|
4
|
+
import state, { saveCache } from '../state/index.js';
|
|
5
|
+
import { getFileHash } from '../utils/hash.js';
|
|
6
|
+
import run from './run.js';
|
|
7
|
+
|
|
8
|
+
export default function createBridgeFile(headerOrModuleFilePath) {
|
|
9
|
+
const interfaceFilePath = upath.resolve(headerOrModuleFilePath);
|
|
10
|
+
if (!fs.existsSync(`${state.config.paths.build}/interface`)) {
|
|
11
|
+
fs.mkdirSync(`${state.config.paths.build}/interface`, { recursive: true });
|
|
12
|
+
}
|
|
13
|
+
if (!fs.existsSync(`${state.config.paths.build}/bridge`)) {
|
|
14
|
+
fs.mkdirSync(`${state.config.paths.build}/bridge`, { recursive: true });
|
|
15
|
+
}
|
|
16
|
+
const interfaceFile = createInterfaceFile(interfaceFilePath);
|
|
17
|
+
return createBridgeFileFromInterfaceFile(interfaceFile);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function createInterfaceFile(headerOrModuleFilePath) {
|
|
21
|
+
if (!headerOrModuleFilePath) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
const fileHash = getFileHash(headerOrModuleFilePath);
|
|
25
|
+
if (state.cache.hashes[headerOrModuleFilePath] === fileHash) {
|
|
26
|
+
return state.cache.interfaces[headerOrModuleFilePath];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const moduleRegex = new RegExp(`.(${state.config.ext.module.join('|')})$`);
|
|
30
|
+
const isModule = moduleRegex.test(headerOrModuleFilePath);
|
|
31
|
+
if (isModule) {
|
|
32
|
+
const newPath = `${state.config.paths.build}/interface/${headerOrModuleFilePath.split('/').pop()}`;
|
|
33
|
+
fs.copyFileSync(headerOrModuleFilePath, newPath);
|
|
34
|
+
state.cache.interfaces[headerOrModuleFilePath] = newPath;
|
|
35
|
+
state.cache.hashes[headerOrModuleFilePath] = fileHash;
|
|
36
|
+
saveCache();
|
|
37
|
+
return newPath;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const headerPaths = (state.config.dependencyParameters?.pathsOfCmakeDepends?.split(';') || [])
|
|
41
|
+
.filter((d) => d.startsWith(state.config.paths.base));
|
|
42
|
+
|
|
43
|
+
const temp2 = headerPaths
|
|
44
|
+
.map((p) => headerOrModuleFilePath.match(new RegExp(`^${p}/.*?/include/(.*?)$`, 'i')))
|
|
45
|
+
.filter((p) => p && p.length === 2);
|
|
46
|
+
|
|
47
|
+
const temp = headerOrModuleFilePath.match(/^(.*)\..+?$/);
|
|
48
|
+
if (temp.length < 2) return null;
|
|
49
|
+
|
|
50
|
+
const filePathWithoutExt = temp[1];
|
|
51
|
+
const interfaceFile = `${filePathWithoutExt}.i`;
|
|
52
|
+
|
|
53
|
+
if (fs.existsSync(interfaceFile)) {
|
|
54
|
+
const newPath = `${state.config.paths.build}/interface/${interfaceFile.split('/').at(-1)}`;
|
|
55
|
+
fs.copyFileSync(interfaceFile, newPath);
|
|
56
|
+
state.cache.interfaces[headerOrModuleFilePath] = newPath;
|
|
57
|
+
state.cache.hashes[headerOrModuleFilePath] = fileHash;
|
|
58
|
+
saveCache();
|
|
59
|
+
return newPath;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const fileName = filePathWithoutExt.split('/').at(-1);
|
|
63
|
+
|
|
64
|
+
let headerPath = state.config.paths.header.find((path) => headerOrModuleFilePath.startsWith(path));
|
|
65
|
+
if (headerPath) headerPath = headerOrModuleFilePath.substr(headerPath.length + 1);
|
|
66
|
+
else if (temp2 && temp2.length > 0) headerPath = temp2[0][1];
|
|
67
|
+
else headerPath = headerOrModuleFilePath.split('/').at(-1);
|
|
68
|
+
|
|
69
|
+
const content = `#ifndef _${fileName.toUpperCase()}_I
|
|
70
|
+
#define _${fileName.toUpperCase()}_I
|
|
71
|
+
|
|
72
|
+
%module ${fileName.toUpperCase()}
|
|
73
|
+
|
|
74
|
+
%{
|
|
75
|
+
#include "${headerPath}"
|
|
76
|
+
%}
|
|
77
|
+
|
|
78
|
+
%feature("shared_ptr");
|
|
79
|
+
%feature("polymorphic_shared_ptr");
|
|
80
|
+
|
|
81
|
+
%include "${headerPath}"
|
|
82
|
+
|
|
83
|
+
#endif
|
|
84
|
+
`;
|
|
85
|
+
const outputFilePath = `${state.config.paths.build}/interface/${fileName}.i`;
|
|
86
|
+
fs.writeFileSync(outputFilePath, content);
|
|
87
|
+
|
|
88
|
+
state.cache.interfaces[headerOrModuleFilePath] = outputFilePath;
|
|
89
|
+
state.cache.hashes[headerOrModuleFilePath] = fileHash;
|
|
90
|
+
saveCache();
|
|
91
|
+
|
|
92
|
+
return outputFilePath;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function createBridgeFileFromInterfaceFile(interfaceFilePath) {
|
|
96
|
+
if (!interfaceFilePath) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const fileHash = getFileHash(interfaceFilePath);
|
|
101
|
+
if (state.cache.hashes[interfaceFilePath] === fileHash) {
|
|
102
|
+
return state.cache.bridges[interfaceFilePath];
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const allHeaders = state.config.dependencyParameters.headerPathWithDepends.split(';');
|
|
106
|
+
|
|
107
|
+
let includePath = [
|
|
108
|
+
...state.config.allDependencies.map((d) => `${d.paths.output}/prebuilt/Emscripten-x86_64/include`),
|
|
109
|
+
...state.config.allDependencies.map((d) => `${d.paths.output}/prebuilt/Emscripten-x86_64/swig`),
|
|
110
|
+
...state.config.paths.header,
|
|
111
|
+
...allHeaders,
|
|
112
|
+
].filter((path) => !!path.toString()).map((path) => `-I${path}`);
|
|
113
|
+
includePath = [...new Set(includePath)];
|
|
114
|
+
|
|
115
|
+
run('swig', [
|
|
116
|
+
'-c++',
|
|
117
|
+
'-embind',
|
|
118
|
+
'-o', `${state.config.paths.build}/bridge/${interfaceFilePath.split('/').at(-1)}.cpp`,
|
|
119
|
+
...includePath,
|
|
120
|
+
interfaceFilePath,
|
|
121
|
+
]);
|
|
122
|
+
|
|
123
|
+
state.cache.bridges[interfaceFilePath] = `${state.config.paths.build}/bridge/${interfaceFilePath.split('/').at(-1)}.cpp`;
|
|
124
|
+
state.cache.hashes[interfaceFilePath] = fileHash;
|
|
125
|
+
saveCache();
|
|
126
|
+
|
|
127
|
+
return state.cache.bridges[interfaceFilePath];
|
|
128
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import replace from 'replace';
|
|
4
|
+
import run from './run.js';
|
|
5
|
+
import getCmakeParameters from './getCmakeParameters.js';
|
|
6
|
+
import state from '../state/index.js';
|
|
7
|
+
|
|
8
|
+
const cpuCount = os.cpus().length - 1;
|
|
9
|
+
const sharedPlatforms = ['Android'];
|
|
10
|
+
|
|
11
|
+
export default function createLib(platform, fileType, options = {}) {
|
|
12
|
+
if (!platform || !options || typeof options !== 'object' || Array.isArray(options)) {
|
|
13
|
+
throw new Error('invalid platform or options');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const basePlatform = platform.split('-', 1)[0];
|
|
17
|
+
if (basePlatform === 'iOS' && process.platform !== 'darwin') {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const buildType = options.isProd ? 'Release' : 'Debug';
|
|
22
|
+
const platformPrefix = `${fileType ? `${fileType}-` : ''}${buildType}`;
|
|
23
|
+
const libdir = `${state.config.paths.build}/${platformPrefix}/prebuilt/${platform}`;
|
|
24
|
+
const buildPath = `${state.config.paths.build}/${platformPrefix}/${platform}`;
|
|
25
|
+
|
|
26
|
+
const buildEnv = { params: [] };
|
|
27
|
+
let buildParams;
|
|
28
|
+
const depPaths = state.config.allDependencyPaths[platform];
|
|
29
|
+
if (state.config.build) {
|
|
30
|
+
const { getBuildParams, getExtraLibs } = state.config.build;
|
|
31
|
+
buildEnv.console = true;
|
|
32
|
+
const ext = sharedPlatforms.includes(basePlatform) ? 'so' : 'a';
|
|
33
|
+
buildParams = getBuildParams ? getBuildParams(platform, depPaths, ext, buildPath) : [];
|
|
34
|
+
if (state.config.build?.buildType !== 'configure') {
|
|
35
|
+
const cmakeBuildType = sharedPlatforms.includes(basePlatform) ? 'SHARED' : 'STATIC';
|
|
36
|
+
buildParams.push(`-DCMAKE_PREFIX_PATH=${libdir}`, `-DCMAKE_FIND_ROOT_PATH=${libdir}`, `-DBUILD_TYPE=${cmakeBuildType}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const cFlags = Object.values(depPaths).map((d) => `-I${d.header}`).join(' ');
|
|
40
|
+
const ldFlags = Object.values(depPaths).map((d) => `-L${d.libPath}`).join(' ');
|
|
41
|
+
let dependLibs = '';
|
|
42
|
+
if (state.config.build?.buildType === 'configure') {
|
|
43
|
+
dependLibs = Object.keys(depPaths).map((d) => `-l${d}`).join(' ');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const extraLibs = getExtraLibs ? getExtraLibs(platform) : [];
|
|
47
|
+
|
|
48
|
+
buildEnv.params.push('-e', `CFLAGS=${cFlags}`);
|
|
49
|
+
buildEnv.params.push('-e', `CPPFLAGS=${cFlags}`);
|
|
50
|
+
buildEnv.params.push('-e', `LDFLAGS=${ldFlags} ${extraLibs.join(' ')}`);
|
|
51
|
+
// buildEnv.params.push('-e', `LIBS=${dependLibs} ${extraLibs.join(' ')}`);
|
|
52
|
+
|
|
53
|
+
state.config.build.env?.forEach((e) => {
|
|
54
|
+
buildEnv.params.push('-e', e);
|
|
55
|
+
});
|
|
56
|
+
} else {
|
|
57
|
+
buildParams = getCmakeParameters(platform, options);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
console.log(`${platform} is compiling...`);
|
|
61
|
+
const t0 = performance.now();
|
|
62
|
+
const cmakeDir = state.config.build ? `${state.config.paths.build}/source` : state.config.paths.cmakeDir;
|
|
63
|
+
|
|
64
|
+
if (state.config.build?.beforeRun) {
|
|
65
|
+
const dataList = state.config.build?.beforeRun(cmakeDir);
|
|
66
|
+
dataList.forEach((data) => {
|
|
67
|
+
run(data.program, data.parameters || [], platformPrefix, platform, buildEnv);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (!options.bypassCmake) {
|
|
72
|
+
if (state.config.build?.buildType === 'configure') {
|
|
73
|
+
fs.cpSync(cmakeDir, buildPath, { recursive: true });
|
|
74
|
+
if (state.config.build?.sourceReplaceList) {
|
|
75
|
+
state.config.build.sourceReplaceList(platform, depPaths)?.forEach(({ regex, replacement, paths }) => {
|
|
76
|
+
replace({
|
|
77
|
+
regex, replacement, paths: paths.map((p) => `${buildPath}/${p}`), recursive: false, silent: true,
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
run(null, [
|
|
82
|
+
'./configure',
|
|
83
|
+
...buildParams,
|
|
84
|
+
`--prefix=${libdir}`,
|
|
85
|
+
], platformPrefix, platform, buildEnv);
|
|
86
|
+
} else {
|
|
87
|
+
run(null, [
|
|
88
|
+
basePlatform === 'iOS' && state.config.build?.useIOSCMake ? 'ios-cmake' : 'cmake', cmakeDir,
|
|
89
|
+
`-DCMAKE_BUILD_TYPE=${buildType}`,
|
|
90
|
+
`-DCMAKE_INSTALL_PREFIX=${libdir}`,
|
|
91
|
+
...buildParams,
|
|
92
|
+
], platformPrefix, platform, buildEnv);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const t1 = performance.now();
|
|
96
|
+
if (basePlatform === 'iOS' && state.config.build?.buildType !== 'configure') {
|
|
97
|
+
const iOSCMakeBuilder = state.config.build?.useIOSCMake ? 'ios-cmake' : 'cmake';
|
|
98
|
+
run(null, [iOSCMakeBuilder, '--build', '.', '-j', cpuCount, '--config', buildType, '--target', 'install'], platformPrefix, platform, { console: buildEnv.console });
|
|
99
|
+
} else {
|
|
100
|
+
run(null, ['make', `-j${cpuCount}`, 'install'], platformPrefix, platform, { console: buildEnv.console });
|
|
101
|
+
}
|
|
102
|
+
const t2 = performance.now();
|
|
103
|
+
console.log(`${platform} compiled`, platformPrefix, `full time: ${Math.round(t2 - t0)}ms`, `cmake: ${Math.round(t1 - t0)}ms`, `build: ${Math.round(t2 - t1)}ms`, `core: ${cpuCount}`);
|
|
104
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import upath from 'upath';
|
|
3
|
+
import { execFileSync } from 'node:child_process';
|
|
4
|
+
import state from '../state/index.js';
|
|
5
|
+
|
|
6
|
+
export default function createXCFramework(overrideConfig = null) {
|
|
7
|
+
if (process.platform !== 'darwin') {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const output = overrideConfig?.paths?.output || state.config.paths.output;
|
|
12
|
+
const projectPath = overrideConfig?.paths?.project || state.config.paths.project;
|
|
13
|
+
const libName = overrideConfig?.export?.libName || state.config.export.libName;
|
|
14
|
+
|
|
15
|
+
if (
|
|
16
|
+
!fs.existsSync(`${output}/prebuilt/iOS-iphoneos/lib`)
|
|
17
|
+
|| !fs.existsSync(`${output}/prebuilt/iOS-iphonesimulator/lib`)
|
|
18
|
+
) return;
|
|
19
|
+
|
|
20
|
+
const options = {
|
|
21
|
+
cwd: projectPath,
|
|
22
|
+
stdio: 'inherit',
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const relativeOutput = upath.relative(projectPath, output);
|
|
26
|
+
|
|
27
|
+
libName.forEach((fileName) => {
|
|
28
|
+
if (!fs.existsSync(`${projectPath}/${fileName}.xcframework`)) {
|
|
29
|
+
const params = [
|
|
30
|
+
'-create-xcframework',
|
|
31
|
+
'-library', `${relativeOutput}/prebuilt/iOS-iphoneos/lib/lib${fileName}.a`,
|
|
32
|
+
'-headers', `${relativeOutput}/prebuilt/iOS-iphoneos/include`,
|
|
33
|
+
'-library', `${relativeOutput}/prebuilt/iOS-iphonesimulator/lib/lib${fileName}.a`,
|
|
34
|
+
'-headers', `${relativeOutput}/prebuilt/iOS-iphonesimulator/include`,
|
|
35
|
+
'-output', `${fileName}.xcframework`,
|
|
36
|
+
];
|
|
37
|
+
execFileSync('xcodebuild', params, options);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (!fs.existsSync(`${output}/prebuilt/${fileName}.xcframework.zip`)) {
|
|
41
|
+
execFileSync('zip', ['-y', '-r', `${relativeOutput}/prebuilt/${fileName}.xcframework.zip`, `${fileName}.xcframework`], options);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import state from '../state/index.js';
|
|
2
|
+
|
|
3
|
+
export default function getCmakeParameters(platform, options = {}) {
|
|
4
|
+
if (!options || typeof options !== 'object' || Array.isArray(options)) {
|
|
5
|
+
throw new Error('invalid options');
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const params = [];
|
|
9
|
+
// if (isBuildBridge) params.push('-DBUILD_BRIDGE=TRUE');
|
|
10
|
+
|
|
11
|
+
const dependParams = state.config.dependencyParameters;
|
|
12
|
+
const externalNativeGlob = [
|
|
13
|
+
...(options.nativeGlob || []),
|
|
14
|
+
];
|
|
15
|
+
const externalBridgeGlob = [
|
|
16
|
+
`${state.config.paths.cli}/assets/commonBridges.cpp`,
|
|
17
|
+
...(options.bridgeGlob || []),
|
|
18
|
+
];
|
|
19
|
+
const nativeGlob = [
|
|
20
|
+
`${state.config.paths.cli}/assets/cppjsEmptySource.cpp`,
|
|
21
|
+
...(dependParams.nativeGlob || []),
|
|
22
|
+
];
|
|
23
|
+
const headerGlob = [
|
|
24
|
+
...(dependParams.headerGlob || []),
|
|
25
|
+
...(options.headerGlob || []),
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
const headerDirs = [
|
|
29
|
+
dependParams.headerPathWithDepends,
|
|
30
|
+
...(options.headerDirs || []),
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
const basePlatform = platform.split('-', 1)[0];
|
|
34
|
+
const sharedPlatforms = ['Android'];
|
|
35
|
+
const buildType = sharedPlatforms.includes(basePlatform) ? 'SHARED' : 'STATIC';
|
|
36
|
+
const otherBuildType = buildType === 'STATIC' ? 'SHARED' : 'STATIC';
|
|
37
|
+
|
|
38
|
+
params.push(...[
|
|
39
|
+
`-DPROJECT_NAME=${options.name || state.config.general.name}`,
|
|
40
|
+
`-DBASE_DIR=${state.config.paths.project}`,
|
|
41
|
+
`-DEXTERNAL_NATIVE_GLOB=${externalNativeGlob.join(';')}`,
|
|
42
|
+
`-DEXTERNAL_BRIDGE_GLOB=${externalBridgeGlob.join(';')}`,
|
|
43
|
+
`-DNATIVE_GLOB=${nativeGlob.join(';')}`,
|
|
44
|
+
`-DHEADER_GLOB=${headerGlob.join(';')}`,
|
|
45
|
+
`-DHEADER_DIR=${headerDirs.join(';')}`,
|
|
46
|
+
`-DDEPENDS_CMAKE_PATHS=${dependParams.pathsOfCmakeDepends}`,
|
|
47
|
+
`-DDEPENDS_CMAKE_NAMES=${dependParams.nameOfCmakeDepends}`,
|
|
48
|
+
`-DBRIDGE_DIR=${state.config.paths.build}/bridge`,
|
|
49
|
+
`-DBUILD_TYPE=${buildType}`,
|
|
50
|
+
`-DBUILD_${otherBuildType}_LIBS=OFF`,
|
|
51
|
+
// '-DCMAKE_CXX_COMPILER_LAUNCHER=ccache',
|
|
52
|
+
...(options.buildSource !== false ? ['-DBUILD_SOURCE=TRUE'] : []),
|
|
53
|
+
]);
|
|
54
|
+
|
|
55
|
+
return params;
|
|
56
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/* eslint-disable default-param-last */
|
|
2
|
+
/* eslint-disable no-param-reassign */
|
|
3
|
+
import state from '../state/index.js';
|
|
4
|
+
|
|
5
|
+
function getRecursiveData(obj, config, dependency, field, platform, subPlatform) {
|
|
6
|
+
const platformName = subPlatform ? `${platform}-${subPlatform}` : platform;
|
|
7
|
+
if (dependency?.platform?.[platformName]?.[field]) {
|
|
8
|
+
Object.entries(dependency.platform[platformName][field]).forEach(([dKey, value]) => {
|
|
9
|
+
if (field === 'data') {
|
|
10
|
+
const key = `${dependency.paths.project}/dist/prebuilt/${platform}/${dKey}`;
|
|
11
|
+
obj[key] = value;
|
|
12
|
+
} else {
|
|
13
|
+
obj[dKey] = value;
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
dependency.dependencies.forEach((dep) => {
|
|
19
|
+
getRecursiveData(obj, config, dep, field, platform, subPlatform);
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default function getData(field, platform = 'Emscripten-x86_64', subPlatform) {
|
|
24
|
+
const output = {};
|
|
25
|
+
getRecursiveData(output, state.config, state.config, field, platform, subPlatform);
|
|
26
|
+
|
|
27
|
+
return output;
|
|
28
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import findFiles from '../utils/findFiles.js';
|
|
2
|
+
import state from '../state/index.js';
|
|
3
|
+
|
|
4
|
+
export default function getDependLibs() {
|
|
5
|
+
let dependLibs = [
|
|
6
|
+
...findFiles(`${state.config.paths.build}/Source-Release/Emscripten-x86_64/dependencies/**/*.a`, { cwd: state.config.paths.project }),
|
|
7
|
+
];
|
|
8
|
+
state.config.dependencyParameters.cmakeDepends.forEach((d) => {
|
|
9
|
+
if (d.export.libName) {
|
|
10
|
+
d.export.libName.forEach((fileName) => {
|
|
11
|
+
if (d.platform['Emscripten-x86_64'].ignoreLibName?.includes(fileName)) return;
|
|
12
|
+
dependLibs.push(...findFiles(`${d.paths.output}/prebuilt/Emscripten-x86_64/lib/lib${fileName}.a`, { cwd: d.paths.project }));
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
dependLibs = [...new Set(dependLibs)];
|
|
18
|
+
return dependLibs;
|
|
19
|
+
}
|