2020-10-15 21:16:52 +09:00
|
|
|
import { execSync } from 'child_process'
|
2020-09-04 17:22:15 +09:00
|
|
|
import { join, parse, sep } from 'path'
|
2020-07-27 00:53:09 +09:00
|
|
|
|
2020-09-04 17:22:15 +09:00
|
|
|
import chalk from 'chalk'
|
2020-07-27 00:53:09 +09:00
|
|
|
import { Command } from 'clipanion'
|
|
|
|
import toml from 'toml'
|
|
|
|
|
2020-09-04 17:22:15 +09:00
|
|
|
import { getNapiConfig } from './consts'
|
|
|
|
import { debugFactory } from './debug'
|
2020-10-15 21:16:52 +09:00
|
|
|
import { getDefaultTargetTriple, parseTriple } from './parse-triple'
|
2020-09-04 17:22:15 +09:00
|
|
|
import { existsAsync, readFileAsync, writeFileAsync } from './utils'
|
|
|
|
|
|
|
|
const debug = debugFactory('build')
|
2020-07-27 00:53:09 +09:00
|
|
|
|
|
|
|
export class BuildCommand extends Command {
|
|
|
|
static usage = Command.Usage({
|
|
|
|
description: 'Copy native module into specified dir',
|
|
|
|
})
|
|
|
|
|
2020-08-21 22:51:14 +09:00
|
|
|
@Command.Boolean(`--platform`)
|
2020-10-15 21:16:52 +09:00
|
|
|
appendPlatformToFilename = false
|
2020-07-27 00:53:09 +09:00
|
|
|
|
|
|
|
@Command.Boolean(`--release`)
|
|
|
|
isRelease = false
|
|
|
|
|
2020-09-04 17:22:15 +09:00
|
|
|
@Command.String('--config,-c')
|
|
|
|
configFileName?: string
|
|
|
|
|
2020-09-05 02:20:30 +09:00
|
|
|
@Command.String('--cargo-name')
|
|
|
|
cargoName?: string
|
|
|
|
|
2020-10-15 21:16:52 +09:00
|
|
|
@Command.String('--target')
|
2020-10-15 17:14:11 +09:00
|
|
|
targetTripleDir = ''
|
|
|
|
|
2020-10-15 21:16:52 +09:00
|
|
|
@Command.String('--features')
|
|
|
|
features?: string
|
|
|
|
|
|
|
|
@Command.String('--cargo-flags')
|
|
|
|
cargoFlags = ''
|
|
|
|
|
2020-09-04 17:22:15 +09:00
|
|
|
@Command.String({
|
|
|
|
required: false,
|
|
|
|
})
|
|
|
|
target = '.'
|
2020-07-27 00:53:09 +09:00
|
|
|
|
|
|
|
@Command.Path('build')
|
|
|
|
async execute() {
|
2020-10-15 21:16:52 +09:00
|
|
|
const releaseFlag = this.isRelease ? `--release` : ''
|
|
|
|
const targetFLag = this.targetTripleDir
|
|
|
|
? `--target ${this.targetTripleDir}`
|
|
|
|
: ''
|
|
|
|
const featuresFlag = this.features ? `--features ${this.features}` : ''
|
|
|
|
const triple = this.targetTripleDir
|
|
|
|
? parseTriple(this.targetTripleDir)
|
|
|
|
: getDefaultTargetTriple(
|
|
|
|
execSync('rustup show active-toolchain', {
|
|
|
|
env: process.env,
|
|
|
|
}).toString('utf8'),
|
|
|
|
)
|
|
|
|
debug(`Current triple is: ${chalk.green(triple.raw)}`)
|
|
|
|
const externalFlags = [
|
|
|
|
releaseFlag,
|
|
|
|
targetFLag,
|
|
|
|
featuresFlag,
|
|
|
|
this.cargoFlags,
|
|
|
|
]
|
|
|
|
.filter((flag) => Boolean(flag))
|
|
|
|
.join(' ')
|
|
|
|
const cargoCommand = `cargo build ${externalFlags}`
|
|
|
|
debug(`Run ${chalk.green(cargoCommand)}`)
|
|
|
|
execSync(cargoCommand, {
|
|
|
|
env: process.env,
|
|
|
|
stdio: 'inherit',
|
|
|
|
})
|
2020-09-04 17:22:15 +09:00
|
|
|
const { binaryName } = getNapiConfig(this.configFileName)
|
2020-09-05 02:20:30 +09:00
|
|
|
let dylibName = this.cargoName
|
|
|
|
if (!dylibName) {
|
|
|
|
let tomlContentString: string
|
|
|
|
let tomlContent: any
|
|
|
|
try {
|
|
|
|
debug('Start read toml')
|
|
|
|
tomlContentString = await readFileAsync(
|
|
|
|
join(process.cwd(), 'Cargo.toml'),
|
|
|
|
'utf-8',
|
|
|
|
)
|
|
|
|
} catch {
|
|
|
|
throw new TypeError(`Could not find Cargo.toml in ${process.cwd()}`)
|
|
|
|
}
|
2020-07-27 00:53:09 +09:00
|
|
|
|
2020-09-05 02:20:30 +09:00
|
|
|
try {
|
|
|
|
debug('Start parse toml')
|
|
|
|
tomlContent = toml.parse(tomlContentString)
|
|
|
|
} catch {
|
|
|
|
throw new TypeError('Could not parse the Cargo.toml')
|
|
|
|
}
|
2020-09-04 17:22:15 +09:00
|
|
|
|
2020-10-10 01:14:09 +09:00
|
|
|
if (tomlContent.package?.name) {
|
2020-09-05 02:20:30 +09:00
|
|
|
dylibName = tomlContent.package.name.replace(/-/g, '_')
|
|
|
|
} else {
|
|
|
|
throw new TypeError('No package.name field in Cargo.toml')
|
|
|
|
}
|
2020-07-27 00:53:09 +09:00
|
|
|
}
|
|
|
|
|
2020-09-04 17:22:15 +09:00
|
|
|
debug(`Dylib name: ${chalk.greenBright(dylibName)}`)
|
|
|
|
|
2020-12-09 16:49:05 +09:00
|
|
|
const platform = triple.platform
|
2020-07-27 00:53:09 +09:00
|
|
|
let libExt
|
2020-09-04 17:22:15 +09:00
|
|
|
|
|
|
|
debug(`Platform: ${chalk.greenBright(platform)}`)
|
2020-07-27 00:53:09 +09:00
|
|
|
|
|
|
|
// Platform based massaging for build commands
|
|
|
|
switch (platform) {
|
|
|
|
case 'darwin':
|
|
|
|
libExt = '.dylib'
|
2020-09-04 17:22:15 +09:00
|
|
|
dylibName = `lib${dylibName}`
|
2020-07-27 00:53:09 +09:00
|
|
|
break
|
|
|
|
case 'win32':
|
|
|
|
libExt = '.dll'
|
|
|
|
break
|
|
|
|
case 'linux':
|
2020-10-14 01:08:22 +09:00
|
|
|
case 'freebsd':
|
2020-10-15 21:16:52 +09:00
|
|
|
case 'openbsd':
|
2020-12-09 16:49:05 +09:00
|
|
|
case 'android':
|
2020-10-15 21:16:52 +09:00
|
|
|
case 'sunos':
|
2020-09-04 17:22:15 +09:00
|
|
|
dylibName = `lib${dylibName}`
|
2020-07-27 00:53:09 +09:00
|
|
|
libExt = '.so'
|
|
|
|
break
|
|
|
|
default:
|
2020-09-04 17:22:15 +09:00
|
|
|
throw new TypeError(
|
2020-07-27 00:53:09 +09:00
|
|
|
'Operating system not currently supported or recognized by the build script',
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2020-10-15 17:14:11 +09:00
|
|
|
const targetDir = join(
|
|
|
|
this.targetTripleDir,
|
|
|
|
this.isRelease ? 'release' : 'debug',
|
|
|
|
)
|
2020-07-27 00:53:09 +09:00
|
|
|
|
2020-08-21 22:51:14 +09:00
|
|
|
const platformName = this.appendPlatformToFilename
|
2020-10-15 21:16:52 +09:00
|
|
|
? `.${triple.platformArchABI}`
|
2020-07-27 00:53:09 +09:00
|
|
|
: ''
|
|
|
|
|
2020-10-15 21:16:52 +09:00
|
|
|
debug(`Platform name: ${platformName || chalk.green('[Empty]')}`)
|
2020-07-27 00:53:09 +09:00
|
|
|
|
2020-09-04 17:22:15 +09:00
|
|
|
let distModulePath = this.target
|
|
|
|
? join(this.target, `${binaryName}${platformName}.node`)
|
|
|
|
: join('target', targetDir, `${binaryName}${platformName}.node`)
|
|
|
|
const parsedDist = parse(distModulePath)
|
2020-07-27 00:53:09 +09:00
|
|
|
|
|
|
|
if (!parsedDist.ext) {
|
|
|
|
distModulePath = `${distModulePath}${platformName}.node`
|
|
|
|
}
|
|
|
|
|
2020-09-04 17:22:15 +09:00
|
|
|
const dir = await findUp()
|
2020-07-27 00:53:09 +09:00
|
|
|
|
2020-09-04 17:22:15 +09:00
|
|
|
if (!dir) {
|
|
|
|
throw new TypeError('No target dir found')
|
|
|
|
}
|
|
|
|
|
|
|
|
const sourcePath = join(dir, 'target', targetDir, `${dylibName}${libExt}`)
|
|
|
|
debug(`Read [${chalk.yellowBright(sourcePath)}] content`)
|
|
|
|
|
|
|
|
const dylibContent = await readFileAsync(sourcePath)
|
|
|
|
|
|
|
|
debug(`Write binary content to [${chalk.yellowBright(distModulePath)}]`)
|
2020-07-27 00:53:09 +09:00
|
|
|
|
|
|
|
await writeFileAsync(distModulePath, dylibContent)
|
|
|
|
}
|
|
|
|
}
|
2020-09-04 17:22:15 +09:00
|
|
|
|
|
|
|
async function findUp(dir = process.cwd()): Promise<string | null> {
|
|
|
|
const dist = join(dir, 'target')
|
|
|
|
if (await existsAsync(dist)) {
|
|
|
|
return dir
|
|
|
|
}
|
|
|
|
const dirs = dir.split(sep)
|
|
|
|
if (dirs.length < 2) {
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
dirs.pop()
|
|
|
|
return findUp(dirs.join(sep))
|
|
|
|
}
|