mirror of
https://github.com/CringeStudios/element-desktop.git
synced 2025-01-18 23:44:59 +01:00
302 lines
10 KiB
TypeScript
302 lines
10 KiB
TypeScript
/*
|
|
Copyright 2020-2021 The Matrix.org Foundation C.I.C.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
import path from "path";
|
|
import childProcess from "child_process";
|
|
import mkdirp from "mkdirp";
|
|
import fsExtra from "fs-extra";
|
|
|
|
import HakEnv from "../../scripts/hak/hakEnv";
|
|
import { DependencyInfo } from "../../scripts/hak/dep";
|
|
|
|
export default async function (hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
|
|
if (hakEnv.isWin()) {
|
|
await buildOpenSslWin(hakEnv, moduleInfo);
|
|
await buildSqlCipherWin(hakEnv, moduleInfo);
|
|
} else if (hakEnv.wantsStaticSqlCipherUnix()) {
|
|
await buildSqlCipherUnix(hakEnv, moduleInfo);
|
|
}
|
|
await buildMatrixSeshat(hakEnv, moduleInfo);
|
|
}
|
|
|
|
async function buildOpenSslWin(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
|
|
const version = moduleInfo.cfg.dependencies.openssl;
|
|
const openSslDir = path.join(moduleInfo.moduleTargetDotHakDir, `openssl-${version}`);
|
|
|
|
const openSslArch = hakEnv.getTargetArch() === "x64" ? "VC-WIN64A" : "VC-WIN32";
|
|
|
|
console.log("Building openssl in " + openSslDir);
|
|
await new Promise<void>((resolve, reject) => {
|
|
const proc = childProcess.spawn(
|
|
"perl",
|
|
[
|
|
"Configure",
|
|
"--prefix=" + moduleInfo.depPrefix,
|
|
// sqlcipher only uses about a tiny part of openssl. We link statically
|
|
// so will only pull in the symbols we use, but we may as well turn off
|
|
// as much as possible to save on build time.
|
|
"no-afalgeng",
|
|
"no-capieng",
|
|
"no-cms",
|
|
"no-ct",
|
|
"no-deprecated",
|
|
"no-dgram",
|
|
"no-dso",
|
|
"no-ec",
|
|
"no-ec2m",
|
|
"no-gost",
|
|
"no-nextprotoneg",
|
|
"no-ocsp",
|
|
"no-sock",
|
|
"no-srp",
|
|
"no-srtp",
|
|
"no-tests",
|
|
"no-ssl",
|
|
"no-tls",
|
|
"no-dtls",
|
|
"no-shared",
|
|
"no-aria",
|
|
"no-camellia",
|
|
"no-cast",
|
|
"no-chacha",
|
|
"no-cmac",
|
|
"no-des",
|
|
"no-dh",
|
|
"no-dsa",
|
|
"no-ecdh",
|
|
"no-ecdsa",
|
|
"no-idea",
|
|
"no-md4",
|
|
"no-mdc2",
|
|
"no-ocb",
|
|
"no-poly1305",
|
|
"no-rc2",
|
|
"no-rc4",
|
|
"no-rmd160",
|
|
"no-scrypt",
|
|
"no-seed",
|
|
"no-siphash",
|
|
"no-sm2",
|
|
"no-sm3",
|
|
"no-sm4",
|
|
"no-whirlpool",
|
|
openSslArch,
|
|
],
|
|
{
|
|
cwd: openSslDir,
|
|
stdio: "inherit",
|
|
},
|
|
);
|
|
proc.on("exit", (code) => {
|
|
code ? reject(code) : resolve();
|
|
});
|
|
});
|
|
|
|
await new Promise<void>((resolve, reject) => {
|
|
const proc = childProcess.spawn("nmake", ["build_libs"], {
|
|
cwd: openSslDir,
|
|
stdio: "inherit",
|
|
});
|
|
proc.on("exit", (code) => {
|
|
code ? reject(code) : resolve();
|
|
});
|
|
});
|
|
|
|
await new Promise<void>((resolve, reject) => {
|
|
const proc = childProcess.spawn("nmake", ["install_dev"], {
|
|
cwd: openSslDir,
|
|
stdio: "inherit",
|
|
});
|
|
proc.on("exit", (code) => {
|
|
code ? reject(code) : resolve();
|
|
});
|
|
});
|
|
}
|
|
|
|
async function buildSqlCipherWin(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
|
|
const version = moduleInfo.cfg.dependencies.sqlcipher;
|
|
const sqlCipherDir = path.join(moduleInfo.moduleTargetDotHakDir, `sqlcipher-${version}`);
|
|
const buildDir = path.join(sqlCipherDir, "bld");
|
|
|
|
await mkdirp(buildDir);
|
|
|
|
await new Promise<void>((resolve, reject) => {
|
|
const proc = childProcess.spawn("nmake", ["/f", path.join("..", "Makefile.msc"), "libsqlite3.lib", "TOP=.."], {
|
|
cwd: buildDir,
|
|
stdio: "inherit",
|
|
env: Object.assign({}, process.env, {
|
|
CCOPTS: "-DSQLITE_HAS_CODEC -I" + path.join(moduleInfo.depPrefix, "include"),
|
|
LTLIBPATHS: "/LIBPATH:" + path.join(moduleInfo.depPrefix, "lib"),
|
|
LTLIBS: "libcrypto.lib",
|
|
}),
|
|
});
|
|
proc.on("exit", (code) => {
|
|
code ? reject(code) : resolve();
|
|
});
|
|
});
|
|
|
|
await fsExtra.copy(path.join(buildDir, "libsqlite3.lib"), path.join(moduleInfo.depPrefix, "lib", "sqlcipher.lib"));
|
|
|
|
await fsExtra.copy(path.join(buildDir, "sqlite3.h"), path.join(moduleInfo.depPrefix, "include", "sqlcipher.h"));
|
|
}
|
|
|
|
async function buildSqlCipherUnix(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
|
|
const version = moduleInfo.cfg.dependencies.sqlcipher;
|
|
const sqlCipherDir = path.join(moduleInfo.moduleTargetDotHakDir, `sqlcipher-${version}`);
|
|
|
|
const args = [
|
|
"--prefix=" + moduleInfo.depPrefix + "",
|
|
"--enable-tempstore=yes",
|
|
"--enable-shared=no",
|
|
"--enable-tcl=no",
|
|
];
|
|
|
|
if (hakEnv.isMac()) {
|
|
args.push("--with-crypto-lib=commoncrypto");
|
|
}
|
|
|
|
if (hakEnv.wantsStaticSqlCipherUnix()) {
|
|
args.push("--enable-tcl=no");
|
|
|
|
if (hakEnv.isLinux()) {
|
|
args.push("--with-pic=yes");
|
|
}
|
|
}
|
|
|
|
if (!hakEnv.isHost()) {
|
|
// In the nonsense world of `configure`, it is assumed you are building
|
|
// a compiler like `gcc`, so the `host` option actually means the target
|
|
// the build output runs on.
|
|
args.push(`--host=${hakEnv.getTargetId()}`);
|
|
}
|
|
|
|
const cflags = ["-DSQLITE_HAS_CODEC"];
|
|
|
|
if (!hakEnv.isHost()) {
|
|
// `clang` uses more logical option naming.
|
|
cflags.push(`--target=${hakEnv.getTargetId()}`);
|
|
}
|
|
|
|
if (cflags.length) {
|
|
args.push(`CFLAGS=${cflags.join(" ")}`);
|
|
}
|
|
|
|
const ldflags: string[] = [];
|
|
|
|
if (hakEnv.isMac()) {
|
|
ldflags.push("-framework Security");
|
|
ldflags.push("-framework Foundation");
|
|
}
|
|
|
|
if (ldflags.length) {
|
|
args.push(`LDFLAGS=${ldflags.join(" ")}`);
|
|
}
|
|
|
|
await new Promise<void>((resolve, reject) => {
|
|
const proc = childProcess.spawn(path.join(sqlCipherDir, "configure"), args, {
|
|
cwd: sqlCipherDir,
|
|
stdio: "inherit",
|
|
});
|
|
proc.on("exit", (code) => {
|
|
code ? reject(code) : resolve();
|
|
});
|
|
});
|
|
|
|
await new Promise<void>((resolve, reject) => {
|
|
const proc = childProcess.spawn("make", [], {
|
|
cwd: sqlCipherDir,
|
|
stdio: "inherit",
|
|
});
|
|
proc.on("exit", (code) => {
|
|
code ? reject(code) : resolve();
|
|
});
|
|
});
|
|
|
|
await new Promise<void>((resolve, reject) => {
|
|
const proc = childProcess.spawn("make", ["install"], {
|
|
cwd: sqlCipherDir,
|
|
stdio: "inherit",
|
|
});
|
|
proc.on("exit", (code) => {
|
|
code ? reject(code) : resolve();
|
|
});
|
|
});
|
|
}
|
|
|
|
async function buildMatrixSeshat(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
|
|
// seshat now uses n-api so we shouldn't need to specify a node version to
|
|
// build against, but it does seems to still need something in here, so leaving
|
|
// it for now: we should confirm how much of this it still actually needs.
|
|
const env = hakEnv.makeGypEnv();
|
|
|
|
if (!hakEnv.isLinux() || hakEnv.wantsStaticSqlCipherUnix()) {
|
|
Object.assign(env, {
|
|
SQLCIPHER_STATIC: 1,
|
|
SQLCIPHER_LIB_DIR: path.join(moduleInfo.depPrefix, "lib"),
|
|
SQLCIPHER_INCLUDE_DIR: path.join(moduleInfo.depPrefix, "include"),
|
|
});
|
|
}
|
|
|
|
if (hakEnv.isLinux() && hakEnv.wantsStaticSqlCipherUnix()) {
|
|
// Ensure Element uses the statically-linked seshat build, and prevent other applications
|
|
// from attempting to use this one. Detailed explanation:
|
|
//
|
|
// RUSTFLAGS
|
|
// An environment variable containing a list of arguments to pass to rustc.
|
|
// -Clink-arg=VALUE
|
|
// A rustc argument to pass a single argument to the linker.
|
|
// -Wl,
|
|
// gcc syntax to pass an argument (from gcc) to the linker (ld).
|
|
// -Bsymbolic:
|
|
// Prefer local/statically linked symbols over those in the environment.
|
|
// Prevent overriding native libraries by LD_PRELOAD etc.
|
|
// --exclude-libs ALL
|
|
// Prevent symbols from being exported by any archive libraries.
|
|
// Reduces output filesize and prevents being dynamically linked against.
|
|
env.RUSTFLAGS = "-Clink-arg=-Wl,-Bsymbolic -Clink-arg=-Wl,--exclude-libs,ALL";
|
|
}
|
|
|
|
if (hakEnv.isWin()) {
|
|
env.RUSTFLAGS = "-Ctarget-feature=+crt-static -Clink-args=libcrypto.lib";
|
|
// Note that in general, you can specify targets in Rust without having to have
|
|
// the matching toolchain, however for this, cargo gets confused when building
|
|
// the build scripts since they run on the host, but vcvarsall.bat sets the c
|
|
// compiler in the path to be the one for the target, so we just use the matching
|
|
// toolchain for the target architecture which makes everything happy.
|
|
env.RUSTUP_TOOLCHAIN = `stable-${hakEnv.getTargetId()}`;
|
|
}
|
|
|
|
if (!hakEnv.isHost()) {
|
|
env.CARGO_BUILD_TARGET = hakEnv.getTargetId();
|
|
}
|
|
|
|
console.log("Running neon with env", env);
|
|
await new Promise<void>((resolve, reject) => {
|
|
const proc = childProcess.spawn(
|
|
path.join(moduleInfo.nodeModuleBinDir, "neon" + (hakEnv.isWin() ? ".cmd" : "")),
|
|
["build", "--release"],
|
|
{
|
|
cwd: moduleInfo.moduleBuildDir,
|
|
env,
|
|
stdio: "inherit",
|
|
},
|
|
);
|
|
proc.on("exit", (code) => {
|
|
code ? reject(code) : resolve();
|
|
});
|
|
});
|
|
}
|