Skip to content

Commit f27e8e1

Browse files
authored
fix(MONGOSH-1808): static building on intel macs and windows (#24)
1 parent 12ec664 commit f27e8e1

File tree

3 files changed

+77
-66
lines changed

3 files changed

+77
-66
lines changed

.github/scripts/libmongocrypt.mjs

Lines changed: 56 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
//@ts-check
1+
// @ts-check
2+
23
import util from 'node:util';
34
import process from 'node:process';
45
import fs from 'node:fs/promises';
@@ -24,7 +25,9 @@ async function parseArguments() {
2425
libVersion: { short: 'l', type: 'string', default: pkg['mongodb:libmongocrypt'] },
2526
clean: { short: 'c', type: 'boolean', default: false },
2627
build: { short: 'b', type: 'boolean', default: false },
28+
dynamic: { type: 'boolean', default: false },
2729
fastDownload: { type: 'boolean', default: false }, // Potentially incorrect download, only for the brave and impatient
30+
'skip-bindings': { type: 'boolean', default: false },
2831
help: { short: 'h', type: 'boolean', default: false }
2932
};
3033

@@ -46,6 +49,8 @@ async function parseArguments() {
4649
fastDownload: args.values.fastDownload,
4750
clean: args.values.clean,
4851
build: args.values.build,
52+
dynamic: args.values.dynamic,
53+
skipBindings: args.values['skip-bindings'],
4954
pkg
5055
};
5156
}
@@ -81,7 +86,7 @@ export async function cloneLibMongoCrypt(libmongocryptRoot, { url, ref }) {
8186
}
8287
}
8388

84-
export async function buildLibMongoCrypt(libmongocryptRoot, nodeDepsRoot) {
89+
export async function buildLibMongoCrypt(libmongocryptRoot, nodeDepsRoot, options) {
8590
console.error('building libmongocrypt...');
8691

8792
const nodeBuildRoot = resolveRoot(nodeDepsRoot, 'tmp', 'libmongocrypt-build');
@@ -115,7 +120,7 @@ export async function buildLibMongoCrypt(libmongocryptRoot, nodeDepsRoot) {
115120
/**
116121
* Where to install libmongocrypt
117122
* Note that `binding.gyp` will set `./deps/include`
118-
* as an include path if BUILD_TYPE=static
123+
* as an include path if libmongocrypt_link_type=static
119124
*/
120125
DCMAKE_INSTALL_PREFIX: nodeDepsRoot
121126
});
@@ -125,18 +130,22 @@ export async function buildLibMongoCrypt(libmongocryptRoot, nodeDepsRoot) {
125130
? toFlags({ Thost: 'x64', A: 'x64', DENABLE_WINDOWS_STATIC_RUNTIME: 'ON' })
126131
: [];
127132

128-
const MACOS_CMAKE_FLAGS =
129-
process.platform === 'darwin' // The minimum macos target version we want for
133+
const DARWIN_CMAKE_FLAGS =
134+
process.platform === 'darwin' // The minimum darwin target version we want for
130135
? toFlags({ DCMAKE_OSX_DEPLOYMENT_TARGET: '10.12' })
131136
: [];
132137

138+
const cmakeProgram = process.platform === 'win32' ? 'cmake.exe' : 'cmake';
139+
133140
await run(
134-
'cmake',
135-
[...CMAKE_FLAGS, ...WINDOWS_CMAKE_FLAGS, ...MACOS_CMAKE_FLAGS, libmongocryptRoot],
136-
{ cwd: nodeBuildRoot }
141+
cmakeProgram,
142+
[...CMAKE_FLAGS, ...WINDOWS_CMAKE_FLAGS, ...DARWIN_CMAKE_FLAGS, libmongocryptRoot],
143+
{ cwd: nodeBuildRoot, shell: process.platform === 'win32' }
137144
);
138-
await run('cmake', ['--build', '.', '--target', 'install', '--config', 'RelWithDebInfo'], {
139-
cwd: nodeBuildRoot
145+
146+
await run(cmakeProgram, ['--build', '.', '--target', 'install', '--config', 'RelWithDebInfo'], {
147+
cwd: nodeBuildRoot,
148+
shell: process.platform === 'win32'
140149
});
141150
}
142151

@@ -228,13 +237,45 @@ export async function downloadLibMongoCrypt(nodeDepsRoot, { ref, fastDownload })
228237
}
229238
}
230239

240+
async function buildBindings(args, pkg) {
241+
await fs.rm(resolveRoot('build'), { force: true, recursive: true });
242+
await fs.rm(resolveRoot('prebuilds'), { force: true, recursive: true });
243+
244+
// install with "ignore-scripts" so that we don't attempt to download a prebuild
245+
await run('npm', ['install', '--ignore-scripts']);
246+
// The prebuild command will make both a .node file in `./build` (local and CI testing will run on current code)
247+
// it will also produce `./prebuilds/mongodb-client-encryption-vVERSION-napi-vNAPI_VERSION-OS-ARCH.tar.gz`.
248+
249+
let gypDefines = process.env.GYP_DEFINES ?? '';
250+
if (args.dynamic) {
251+
gypDefines += ' libmongocrypt_link_type=dynamic';
252+
}
253+
254+
gypDefines = gypDefines.trim();
255+
const prebuildOptions =
256+
gypDefines.length > 0
257+
? { env: { ...process.env, GYP_DEFINES: gypDefines } }
258+
: undefined;
259+
260+
await run('npm', ['run', 'prebuild'], prebuildOptions);
261+
// Compile Typescript
262+
await run('npm', ['run', 'prepare']);
263+
264+
if (process.platform === 'darwin' && process.arch === 'arm64') {
265+
// The "arm64" build is actually a universal binary
266+
const armTar = `mongodb-client-encryption-v${pkg.version}-napi-v4-darwin-arm64.tar.gz`;
267+
const x64Tar = `mongodb-client-encryption-v${pkg.version}-napi-v4-darwin-x64.tar.gz`;
268+
await fs.copyFile(resolveRoot('prebuilds', armTar), resolveRoot('prebuilds', x64Tar));
269+
}
270+
}
271+
231272
async function main() {
232273
const { pkg, ...args } = await parseArguments();
233274
console.log(args);
234275

235276
const nodeDepsDir = resolveRoot('deps');
236277

237-
if (args.build) {
278+
if (args.build && !args.dynamic) {
238279
const libmongocryptCloneDir = resolveRoot('_libmongocrypt');
239280

240281
const currentLibMongoCryptBranch = await fs
@@ -252,36 +293,15 @@ async function main() {
252293
const isBuilt = libmongocryptBuiltVersion.trim() === args.ref;
253294

254295
if (args.clean || !isBuilt) {
255-
await buildLibMongoCrypt(libmongocryptCloneDir, nodeDepsDir);
296+
await buildLibMongoCrypt(libmongocryptCloneDir, nodeDepsDir, args);
256297
}
257-
} else {
298+
} else if (!args.dynamic) {
258299
// Download
259300
await downloadLibMongoCrypt(nodeDepsDir, args);
260301
}
261302

262-
await fs.rm(resolveRoot('build'), { force: true, recursive: true });
263-
await fs.rm(resolveRoot('prebuilds'), { force: true, recursive: true });
264-
265-
// install with "ignore-scripts" so that we don't attempt to download a prebuild
266-
await run('npm', ['install', '--ignore-scripts']);
267-
// The prebuild command will make both a .node file in `./build` (local and CI testing will run on current code)
268-
// it will also produce `./prebuilds/mongodb-client-encryption-vVERSION-napi-vNAPI_VERSION-OS-ARCH.tar.gz`.
269-
await run('npm', ['run', 'prebuild']);
270-
// Compile Typescript
271-
await run('npm', ['run', 'prepare']);
272-
273-
if (process.platform === 'darwin') {
274-
// The "arm64" build is actually a universal binary
275-
await fs.copyFile(
276-
resolveRoot(
277-
'prebuilds',
278-
`mongodb-client-encryption-v${pkg.version}-napi-v4-darwin-arm64.tar.gz`
279-
),
280-
resolveRoot(
281-
'prebuilds',
282-
`mongodb-client-encryption-v${pkg.version}-napi-v4-darwin-x64.tar.gz`
283-
)
284-
);
303+
if (!args.skipBindings) {
304+
await buildBindings(args, pkg);
285305
}
286306
}
287307

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ npm run install:libmongocrypt
6565
#### `libmongocrypt.mjs`
6666

6767
```
68-
node libmongocrypt.mjs [--gitURL=string] [--libVersion=string] [--clean] [--build] [--no-crypto] [--fastDownload]
68+
node libmongocrypt.mjs [optional flags]
6969
7070
By default attempts to download and compile the bindings with the crypto prebuilds of libmongocrypt.
7171
Can be configured to clone and build without crypto.
@@ -75,6 +75,9 @@ Can be configured to clone and build without crypto.
7575
You may use "latest" to get current libmongocrypt `HEAD`.
7676
--clean Combined with --build, the script will not skip cloning and rebuilding libmongocrypt.
7777
--build Instead of downloading, clone and build libmongocrypt along with the bindings.
78+
--dynamic Skips cloning or downloading libmongocrypt, runs prebuild with build_type set to "dynamic" to compile
79+
a prebuild that links to a system copy of libmongocrypt.
80+
--skip-bindings Skips running prebuild. Useful if only the libmongocrypt dependency is desired.
7881
7982
Only suitable for local development:
8083

binding.gyp

Lines changed: 17 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,13 @@
11
{
22
'targets': [{
33
'target_name': 'mongocrypt',
4+
'type': 'loadable_module',
45
'include_dirs': [
56
"<!(node -p \"require('node-addon-api').include_dir\")",
67
],
78
'variables': {
8-
'variables': {
9-
'build_type%': "dynamic",
10-
},
11-
'conditions': [
12-
['OS=="win"', {
13-
'build_type' : "<!(echo %BUILD_TYPE%)"
14-
}],
15-
['OS!="win"', {
16-
'build_type' : "<!(echo $BUILD_TYPE)",
17-
}]
18-
]
9+
'ARCH': '<(host_arch)',
10+
'libmongocrypt_link_type%': 'static',
1911
},
2012
'sources': [
2113
'addon/mongocrypt.cc'
@@ -24,35 +16,31 @@
2416
'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
2517
'CLANG_CXX_LIBRARY': 'libc++',
2618
'MACOSX_DEPLOYMENT_TARGET': '10.12',
27-
"OTHER_CFLAGS": [
28-
"-arch x86_64",
29-
"-arch arm64"
30-
],
31-
"OTHER_LDFLAGS": [
32-
"-arch x86_64",
33-
"-arch arm64"
34-
]
19+
'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden
3520
},
3621
'cflags!': [ '-fno-exceptions' ],
3722
'cflags_cc!': [ '-fno-exceptions' ],
3823
'msvs_settings': {
3924
'VCCLCompilerTool': { 'ExceptionHandling': 1 },
4025
},
4126
'conditions': [
42-
['OS=="mac"', {
43-
'cflags+': ['-fvisibility=hidden'],
27+
['OS=="mac"', { 'cflags+': ['-fvisibility=hidden'] }],
28+
['_type!="static_library" and ARCH=="arm64"', {
4429
'xcode_settings': {
45-
'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden
30+
"OTHER_CFLAGS": [
31+
"-arch x86_64",
32+
"-arch arm64"
33+
],
34+
"OTHER_LDFLAGS": [
35+
"-arch x86_64",
36+
"-arch arm64"
37+
]
4638
}
4739
}],
48-
['build_type=="dynamic"', {
49-
'link_settings': {
50-
'libraries': [
51-
'-lmongocrypt'
52-
]
53-
}
40+
['libmongocrypt_link_type=="dynamic"', {
41+
'link_settings': { 'libraries': ['-lmongocrypt'] }
5442
}],
55-
['build_type!="dynamic"', {
43+
['libmongocrypt_link_type=="static"', {
5644
'conditions': [
5745
['OS!="win"', {
5846
'include_dirs': [

0 commit comments

Comments
 (0)