Skip to content

Commit

Permalink
fix(MONGOSH-1808): static building on intel macs and windows (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
nbbeeken authored Jun 28, 2024
1 parent 12ec664 commit f27e8e1
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 66 deletions.
92 changes: 56 additions & 36 deletions .github/scripts/libmongocrypt.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//@ts-check
// @ts-check

import util from 'node:util';
import process from 'node:process';
import fs from 'node:fs/promises';
Expand All @@ -24,7 +25,9 @@ async function parseArguments() {
libVersion: { short: 'l', type: 'string', default: pkg['mongodb:libmongocrypt'] },
clean: { short: 'c', type: 'boolean', default: false },
build: { short: 'b', type: 'boolean', default: false },
dynamic: { type: 'boolean', default: false },
fastDownload: { type: 'boolean', default: false }, // Potentially incorrect download, only for the brave and impatient
'skip-bindings': { type: 'boolean', default: false },
help: { short: 'h', type: 'boolean', default: false }
};

Expand All @@ -46,6 +49,8 @@ async function parseArguments() {
fastDownload: args.values.fastDownload,
clean: args.values.clean,
build: args.values.build,
dynamic: args.values.dynamic,
skipBindings: args.values['skip-bindings'],
pkg
};
}
Expand Down Expand Up @@ -81,7 +86,7 @@ export async function cloneLibMongoCrypt(libmongocryptRoot, { url, ref }) {
}
}

export async function buildLibMongoCrypt(libmongocryptRoot, nodeDepsRoot) {
export async function buildLibMongoCrypt(libmongocryptRoot, nodeDepsRoot, options) {
console.error('building libmongocrypt...');

const nodeBuildRoot = resolveRoot(nodeDepsRoot, 'tmp', 'libmongocrypt-build');
Expand Down Expand Up @@ -115,7 +120,7 @@ export async function buildLibMongoCrypt(libmongocryptRoot, nodeDepsRoot) {
/**
* Where to install libmongocrypt
* Note that `binding.gyp` will set `./deps/include`
* as an include path if BUILD_TYPE=static
* as an include path if libmongocrypt_link_type=static
*/
DCMAKE_INSTALL_PREFIX: nodeDepsRoot
});
Expand All @@ -125,18 +130,22 @@ export async function buildLibMongoCrypt(libmongocryptRoot, nodeDepsRoot) {
? toFlags({ Thost: 'x64', A: 'x64', DENABLE_WINDOWS_STATIC_RUNTIME: 'ON' })
: [];

const MACOS_CMAKE_FLAGS =
process.platform === 'darwin' // The minimum macos target version we want for
const DARWIN_CMAKE_FLAGS =
process.platform === 'darwin' // The minimum darwin target version we want for
? toFlags({ DCMAKE_OSX_DEPLOYMENT_TARGET: '10.12' })
: [];

const cmakeProgram = process.platform === 'win32' ? 'cmake.exe' : 'cmake';

await run(
'cmake',
[...CMAKE_FLAGS, ...WINDOWS_CMAKE_FLAGS, ...MACOS_CMAKE_FLAGS, libmongocryptRoot],
{ cwd: nodeBuildRoot }
cmakeProgram,
[...CMAKE_FLAGS, ...WINDOWS_CMAKE_FLAGS, ...DARWIN_CMAKE_FLAGS, libmongocryptRoot],
{ cwd: nodeBuildRoot, shell: process.platform === 'win32' }
);
await run('cmake', ['--build', '.', '--target', 'install', '--config', 'RelWithDebInfo'], {
cwd: nodeBuildRoot

await run(cmakeProgram, ['--build', '.', '--target', 'install', '--config', 'RelWithDebInfo'], {
cwd: nodeBuildRoot,
shell: process.platform === 'win32'
});
}

Expand Down Expand Up @@ -228,13 +237,45 @@ export async function downloadLibMongoCrypt(nodeDepsRoot, { ref, fastDownload })
}
}

async function buildBindings(args, pkg) {
await fs.rm(resolveRoot('build'), { force: true, recursive: true });
await fs.rm(resolveRoot('prebuilds'), { force: true, recursive: true });

// install with "ignore-scripts" so that we don't attempt to download a prebuild
await run('npm', ['install', '--ignore-scripts']);
// The prebuild command will make both a .node file in `./build` (local and CI testing will run on current code)
// it will also produce `./prebuilds/mongodb-client-encryption-vVERSION-napi-vNAPI_VERSION-OS-ARCH.tar.gz`.

let gypDefines = process.env.GYP_DEFINES ?? '';
if (args.dynamic) {
gypDefines += ' libmongocrypt_link_type=dynamic';
}

gypDefines = gypDefines.trim();
const prebuildOptions =
gypDefines.length > 0
? { env: { ...process.env, GYP_DEFINES: gypDefines } }
: undefined;

await run('npm', ['run', 'prebuild'], prebuildOptions);
// Compile Typescript
await run('npm', ['run', 'prepare']);

if (process.platform === 'darwin' && process.arch === 'arm64') {
// The "arm64" build is actually a universal binary
const armTar = `mongodb-client-encryption-v${pkg.version}-napi-v4-darwin-arm64.tar.gz`;
const x64Tar = `mongodb-client-encryption-v${pkg.version}-napi-v4-darwin-x64.tar.gz`;
await fs.copyFile(resolveRoot('prebuilds', armTar), resolveRoot('prebuilds', x64Tar));
}
}

async function main() {
const { pkg, ...args } = await parseArguments();
console.log(args);

const nodeDepsDir = resolveRoot('deps');

if (args.build) {
if (args.build && !args.dynamic) {
const libmongocryptCloneDir = resolveRoot('_libmongocrypt');

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

if (args.clean || !isBuilt) {
await buildLibMongoCrypt(libmongocryptCloneDir, nodeDepsDir);
await buildLibMongoCrypt(libmongocryptCloneDir, nodeDepsDir, args);
}
} else {
} else if (!args.dynamic) {
// Download
await downloadLibMongoCrypt(nodeDepsDir, args);
}

await fs.rm(resolveRoot('build'), { force: true, recursive: true });
await fs.rm(resolveRoot('prebuilds'), { force: true, recursive: true });

// install with "ignore-scripts" so that we don't attempt to download a prebuild
await run('npm', ['install', '--ignore-scripts']);
// The prebuild command will make both a .node file in `./build` (local and CI testing will run on current code)
// it will also produce `./prebuilds/mongodb-client-encryption-vVERSION-napi-vNAPI_VERSION-OS-ARCH.tar.gz`.
await run('npm', ['run', 'prebuild']);
// Compile Typescript
await run('npm', ['run', 'prepare']);

if (process.platform === 'darwin') {
// The "arm64" build is actually a universal binary
await fs.copyFile(
resolveRoot(
'prebuilds',
`mongodb-client-encryption-v${pkg.version}-napi-v4-darwin-arm64.tar.gz`
),
resolveRoot(
'prebuilds',
`mongodb-client-encryption-v${pkg.version}-napi-v4-darwin-x64.tar.gz`
)
);
if (!args.skipBindings) {
await buildBindings(args, pkg);
}
}

Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ npm run install:libmongocrypt
#### `libmongocrypt.mjs`

```
node libmongocrypt.mjs [--gitURL=string] [--libVersion=string] [--clean] [--build] [--no-crypto] [--fastDownload]
node libmongocrypt.mjs [optional flags]
By default attempts to download and compile the bindings with the crypto prebuilds of libmongocrypt.
Can be configured to clone and build without crypto.
Expand All @@ -75,6 +75,9 @@ Can be configured to clone and build without crypto.
You may use "latest" to get current libmongocrypt `HEAD`.
--clean Combined with --build, the script will not skip cloning and rebuilding libmongocrypt.
--build Instead of downloading, clone and build libmongocrypt along with the bindings.
--dynamic Skips cloning or downloading libmongocrypt, runs prebuild with build_type set to "dynamic" to compile
a prebuild that links to a system copy of libmongocrypt.
--skip-bindings Skips running prebuild. Useful if only the libmongocrypt dependency is desired.
Only suitable for local development:
Expand Down
46 changes: 17 additions & 29 deletions binding.gyp
Original file line number Diff line number Diff line change
@@ -1,21 +1,13 @@
{
'targets': [{
'target_name': 'mongocrypt',
'type': 'loadable_module',
'include_dirs': [
"<!(node -p \"require('node-addon-api').include_dir\")",
],
'variables': {
'variables': {
'build_type%': "dynamic",
},
'conditions': [
['OS=="win"', {
'build_type' : "<!(echo %BUILD_TYPE%)"
}],
['OS!="win"', {
'build_type' : "<!(echo $BUILD_TYPE)",
}]
]
'ARCH': '<(host_arch)',
'libmongocrypt_link_type%': 'static',
},
'sources': [
'addon/mongocrypt.cc'
Expand All @@ -24,35 +16,31 @@
'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
'CLANG_CXX_LIBRARY': 'libc++',
'MACOSX_DEPLOYMENT_TARGET': '10.12',
"OTHER_CFLAGS": [
"-arch x86_64",
"-arch arm64"
],
"OTHER_LDFLAGS": [
"-arch x86_64",
"-arch arm64"
]
'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden
},
'cflags!': [ '-fno-exceptions' ],
'cflags_cc!': [ '-fno-exceptions' ],
'msvs_settings': {
'VCCLCompilerTool': { 'ExceptionHandling': 1 },
},
'conditions': [
['OS=="mac"', {
'cflags+': ['-fvisibility=hidden'],
['OS=="mac"', { 'cflags+': ['-fvisibility=hidden'] }],
['_type!="static_library" and ARCH=="arm64"', {
'xcode_settings': {
'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden
"OTHER_CFLAGS": [
"-arch x86_64",
"-arch arm64"
],
"OTHER_LDFLAGS": [
"-arch x86_64",
"-arch arm64"
]
}
}],
['build_type=="dynamic"', {
'link_settings': {
'libraries': [
'-lmongocrypt'
]
}
['libmongocrypt_link_type=="dynamic"', {
'link_settings': { 'libraries': ['-lmongocrypt'] }
}],
['build_type!="dynamic"', {
['libmongocrypt_link_type=="static"', {
'conditions': [
['OS!="win"', {
'include_dirs': [
Expand Down

0 comments on commit f27e8e1

Please sign in to comment.