├── .dockerignore ├── .gitignore ├── CHANGELOG.md ├── README.md ├── builder ├── build_and_export_qjs.sh ├── custom │ ├── README.md │ ├── musl │ │ ├── bin │ │ │ └── musl-gcc │ │ └── lib │ │ │ └── musl-gcc.specs │ └── qjs │ │ ├── examples │ │ └── ext-lib │ │ │ ├── example1.js │ │ │ ├── example2.js │ │ │ ├── example3.js │ │ │ └── example4.js │ │ ├── files │ │ ├── path.c │ │ └── path.h │ │ ├── patches │ │ ├── 2020-09-06 │ │ │ ├── Makefile.patch │ │ │ └── qjsc.patch │ │ ├── 2020-11-08 │ │ │ ├── Makefile.patch │ │ │ ├── qjs.patch │ │ │ ├── qjsc.patch │ │ │ └── quickjs-libc.patch │ │ ├── 2021-03-27 │ │ │ ├── Makefile.patch │ │ │ ├── qjs.patch │ │ │ ├── qjsc.patch │ │ │ └── quickjs-libc.patch │ │ ├── 2023-12-09 │ │ │ ├── Makefile.patch │ │ │ ├── qjs.patch │ │ │ ├── qjsc.patch │ │ │ └── quickjs-libc.patch │ │ ├── 2024-01-13 │ │ │ ├── Makefile.patch │ │ │ ├── qjs.patch │ │ │ ├── qjsc.patch │ │ │ └── quickjs-libc.patch │ │ └── 2025-04-26 │ │ │ ├── Makefile.patch │ │ │ ├── qjs.patch │ │ │ ├── qjsc.patch │ │ │ └── quickjs-libc.patch │ │ ├── qjsc-x86_64 │ │ └── scripts │ │ ├── examples │ │ └── compile_examples.sh │ │ ├── qjs.sh │ │ └── qjsc.sh ├── env │ ├── deps │ └── qjs └── scripts │ ├── bootstrap-alpine.sh │ ├── build_deps.sh │ ├── build_qjs.sh │ ├── checkout_qjs.sh │ ├── export_qjs.sh │ ├── fetch_deps.sh │ └── prepare_qjs.sh ├── docker ├── Dockerfile ├── build_and_export_qjs.sh └── scripts │ └── build_docker_image.sh ├── flake.lock └── flake.nix /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | deps 3 | packages 4 | quickjs-repo 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | deps 2 | packages 3 | quickjs-repo 4 | 5 | .history -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## [2025-04-26_1] 4 | 5 | * chore: QuickJS release `2025-04-26` 6 | 7 | ## [2024-01-13_3] 8 | 9 | * refactor: refactor: use `type -p` instead of `which` in `qjsc.sh` 10 | 11 | ## [2024-01-13_2] 12 | 13 | * feat: improve `js_os_exec` performances by computing `fd_max` using `/proc` 14 | 15 | ## [2024-01-13_1] 16 | 17 | * chore: QuickJS release `2024-01-13` 18 | 19 | ## [2023-12-09_1] 20 | 21 | * chore: QuickJS release `2023-12-09` 22 | 23 | ## [2021-03-27_4] 24 | 25 | * feat: expose `mkdtemp` function to javascript 26 | 27 | ## [2021-03-27_3] 28 | 29 | * feat: expose `flock` function to javascript 30 | * feat: expose `mkstemp` function to javascript 31 | * fix: don't call [upx](https://upx.github.io/) if compilation failed 32 | 33 | ## [2021-03-27_2] 34 | 35 | * refactor: built [using](https://github.com/ctn-malone/musl-cross-maker/releases/tag/gcc-6.5.0_binutils-2.25.1_musl-1.2.2) 36 | * gcc : 6.5.0 37 | * binutils : 2.25.1 38 | * musl : 1.2.2 39 | * feat: QuickJS binaries are compressed using [upx](https://upx.github.io/) by default 40 | * feat: compiled files are compressed using [upx](https://upx.github.io/) by default (if possible) 41 | * feat: support for `QJS_LIB_DIR` environment variable 42 | * feat: expose `getpid` function to javascript 43 | 44 | ## [2021-03-27_1] 45 | 46 | * QuickJS release `2021-03-27` 47 | 48 | ## [2020-11-08_3] 49 | 50 | * Possibility to embed https://github.com/ctn-malone/qjs-ext-lib when building packages 51 | 52 | ## [2020-11-08_2] 53 | 54 | * Possibility to embed custom javascript modules when building packages 55 | * Fallback to the directory containing `qjs` & `qjsc` binaries when resolving imports 56 | 57 | ## [2020-11-08_1] 58 | 59 | * *QuickJS* release `2020-11-08` 60 | 61 | ## [2020-09-06_1] 62 | 63 | * *QuickJS* release `2020-09-06` 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Cross compile [QuickJS](https://bellard.org/quickjs/quickjs.html) interpreter & compiler statically. Resulting [QuickJS](https://github.com/ctn-malone/quickjs-cross-compiler) compiler also generates *static* binaries based on [musl libc](https://musl.libc.org/) 2 | 3 | Following target architectures are supported 4 | 5 | * x86_64 6 | * i686 7 | * armv7l 8 | * aarch64 9 | 10 | Cross compilation is performed using [musl.cc](https://github.com/ctn-malone/musl-cross-maker) static compilers (which means you should be able to generate a portable package of *QuickJS* from any recent *x86_64* Linux distribution with *gcc*) 11 | 12 | Final portable version should weight around 7MB (after decompression) 13 | 14 | Static compiler should work with any Linux distribution with *gcc* >= `4.3.2` and *binutils* >= `2.25` 15 | 16 | By default, packages will be exported to `packages` directory, at the root of the repository 17 | 18 | Don't forget to check the [qjs-ext-lib](https://github.com/ctn-malone/qjs-ext-lib) repo which provides some 19 | wrappers around common unix tools to do HTTP requests or execute external programs (and more) 😊 20 | 21 | **Table of content** 22 | - [Extra functions](#extra-functions) 23 | - [os.flock](#osflock) 24 | - [os.mkstemp](#osmkstemp) 25 | - [os.mkdtemp](#osmkdtemp) 26 | - [Other changes](#other-changes) 27 | - [Generate a portable package using *Docker*](#generate-a-portable-package-using-docker) 28 | - [Generate a portable package without using *Docker*](#generate-a-portable-package-without-using-docker) 29 | - [Using the portable compiler](#using-the-portable-compiler) 30 | - [Nix](#nix) 31 | - [Embed custom javascript modules](#embed-custom-javascript-modules) 32 | - [Embed QuickJS extension library](#embed-quickjs-extension-library) 33 | - [Limitations](#limitations) 34 | 35 | # Extra functions 36 | 37 | Some extra functions not part of [vanilla QuickJS](https://bellard.org/quickjs/quickjs.html) have been added 38 | 39 | ## os.flock 40 | 41 | `os.flock(fd, operation)` 42 | 43 | See https://linux.die.net/man/2/flock 44 | 45 | Example 46 | 47 | ``` 48 | const fd = os.open('/tmp/lock', os.O_RDWR | os.O_CREAT, 0o644); 49 | // code will block until no other process is accessing the file 50 | os.flock(fd, os.LOCK_EX); 51 | ``` 52 | 53 | ## os.mkstemp 54 | 55 | `os.mkstemp(template, outputObj)` 56 | 57 | See https://man7.org/linux/man-pages/man3/mkstemp.3.html 58 | 59 | Example 60 | 61 | ``` 62 | const outputObj = {}; 63 | // template MUST end with XXXXXX 64 | const fd = os.mkstemp('/tmp/randomXXXXXX', outputObj); 65 | std.puts(outputObj.filename) 66 | ``` 67 | 68 | ## os.mkdtemp 69 | 70 | `os.mkdtemp(template, errObj)` 71 | 72 | See https://man7.org/linux/man-pages/man3/mkdtemp.3.html 73 | 74 | Example 75 | 76 | ``` 77 | const errObj = {}; 78 | // template MUST end with XXXXXX 79 | const dirname = os.mkdtemp('/tmp/randomXXXXXX', errObj); 80 | std.puts(dirname) 81 | ``` 82 | 83 | # Other changes 84 | 85 | - improve `js_os_exec` performances by computing `fd_max` using `/proc` 86 | 87 | # Generate a portable package using *Docker* 88 | 89 | NB : This is the recommended way 90 | 91 | A portable package containing interpreter & compiler can be generated using `docker/build_and_export_qjs.sh` script 92 | 93 | ``` 94 | ./docker/build_and_export_qjs.sh -h 95 | Build a static version of QuickJS (interpreter & compiler) 96 | Usage: ./docker/build_and_export_qjs.sh [-p|--packages-dir ] [-a|--arch ] [--(no-)ext-lib] [--ext-lib-version ] [-e|--extra-dir ] [--(no-)force-build-image] [-v|--(no-)verbose] [-u|--(no-)upx] [-h|--help] [] 97 | : QuickJS version (ex: 2020-09-06) (default: '2025-04-26') 98 | -p, --packages-dir: directory where package will be exported (default: './packages') 99 | -a, --arch: target architecture. Can be one of: 'x86_64', 'i686', 'armv7l' and 'aarch64' (default: 'x86_64') 100 | --ext-lib, --no-ext-lib: add QuickJS extension library (off by default) 101 | --ext-lib-version: QuickJS extension library version (default: '0.14.2') 102 | -e, --extra-dir: extra directory to add into package (empty by default) 103 | --force-build-image, --no-force-build-image: force rebuilding docker image (off by default) 104 | -v, --verbose, --no-verbose: enable verbose mode (off by default) 105 | -u, --upx, --no-upx: compress binaries using upx (on by default) 106 | -h, --help: Prints help 107 | ``` 108 | 109 | Examples 110 | 111 | ``` 112 | ./docker/build_and_export_qjs.sh -v 113 | ``` 114 | 115 | Above command will : 116 | 117 | * build a *Docker* image (only if it does not already exist) which will download and build necessary dependencies 118 | * run a temporary container and : 119 | * enable verbose mode inside the container 120 | * build *default* *QuickJS* version (`2025-04-26` as of 2025-04-26) for *default* architecture (`x86_64`) 121 | * export portable package to *default* location (`packages` directory at the root of the repository) 122 | 123 | ``` 124 | for arch in x86_64 i686 armv7l aarch64 ; do ./docker/build_and_export_qjs.sh -va ${arch} ; done 125 | ``` 126 | 127 | Same as previous command but will build packages for multiple target architectures 128 | 129 | # Generate a portable package without using *Docker* 130 | 131 | A portable package containing interpreter & compiler can be generated using `builder/build_and_export_qjs.sh` script 132 | 133 | ``` 134 | ./builder/build_and_export_qjs.sh -h 135 | Build a static version of QuickJS (interpreter & compiler) 136 | Usage: ./builder/build_and_export_qjs.sh [-p|--packages-dir ] [--deps-dir ] [-a|--arch ] [--(no-)ext-lib] [--ext-lib-version ] [-e|--extra-dir ] [--(no-)force-fetch-deps] [--(no-)force-build-deps] [--(no-)force-checkout-qjs] [--(no-)force-build-qjs] [-v|--(no-)verbose] [-u|--(no-)upx] [-h|--help] [] 137 | : QuickJS version (ex: 2020-09-06) (default: '2025-04-26') 138 | -p, --packages-dir: directory where package will be exported (default: './packages') 139 | --deps-dir: directory where dependencies should be stored/buil (default: './deps') 140 | -a, --arch: target architecture. Can be one of: 'x86_64', 'i686', 'armv7l' and 'aarch64' (default: 'x86_64') 141 | --ext-lib, --no-ext-lib: add QuickJS extension library (off by default) 142 | --ext-lib-version: QuickJS extension library version (default: '0.14.2') 143 | -e, --extra-dir: extra directory to add into package (empty by default) 144 | --force-fetch-deps, --no-force-fetch-deps: force re-fetching dependencies (off by default) 145 | --force-build-deps, --no-force-build-deps: force rebuild of dependencies (off by default) 146 | --force-checkout-qjs, --no-force-checkout-qjs: clone repository even if it exists (off by default) 147 | --force-build-qjs, --no-force-build-qjs: force rebuild of QuickJS (off by default) 148 | -v, --verbose, --no-verbose: enable verbose mode (off by default) 149 | -u, --upx, --no-upx: compress binaries using upx (on by default) 150 | -h, --help: Prints help 151 | ``` 152 | 153 | Examples 154 | 155 | ``` 156 | ./builder/build_and_export_qjs.sh 157 | ``` 158 | 159 | Above command will : 160 | 161 | * download and build necessary dependencies under *default* location (`deps` directory at the root of the repository) 162 | * build *default* *QuickJS* version (`2025-04-26` as of 2024-01-14) for *default* architecture (`x86_64`) 163 | * export portable package to *default* location (`packages` directory at the root of the repository) 164 | 165 | ``` 166 | ./builder/build_and_export_qjs.sh '2025-04-26' -a armv7l -p /usr/local/packages -d /usr/local/deps -v 167 | ``` 168 | 169 | Above command will : 170 | 171 | * build *QuickJS* version `2025-04-26` for `armv7l` architecture 172 | * download and build necessary dependencies under `/usr/local/deps` 173 | * export portable package to `/usr/local/packages` 174 | * enable verbose mode 175 | 176 | # Using the portable compiler 177 | 178 | Assuming [package](https://github.com/ctn-malone/quickjs-cross-compiler/releases) was decompressed under `/usr/local/quickjs`, just run `/usr/local/quickjs/qjsc.sh` to compile a `.js` file 179 | 180 | Example `hello.js` file 181 | 182 | ```javascript 183 | import * as std from "std"; 184 | 185 | let name = 'world'; 186 | if (undefined !== scriptArgs[1]) { 187 | name = scriptArgs[1]; 188 | } 189 | console.log(`Hello ${name} !`); 190 | 191 | while (true) { 192 | console.log(`Type 'exit' to exit script`); 193 | const str = std.in.getline(); 194 | if ('exit' == str) { 195 | break; 196 | } 197 | } 198 | console.log(`Goodbye ${name}!`); 199 | ``` 200 | 201 | File can be compiled using 202 | 203 | ``` 204 | /usr/local/quickjs/qjsc.sh -o hello hello.js 205 | ``` 206 | 207 | ``` 208 | ls -l hello 209 | -rwxrwxr-x 1 user user 899160 oct. 19 15:32 hello 210 | ``` 211 | 212 | ``` 213 | file hello 214 | hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped 215 | ``` 216 | 217 | ``` 218 | ldd hello 219 | not a dynamic executable 220 | ``` 221 | 222 | NB : if [upx](https://upx.github.io/) exists, resulting binary will be automatically compressed (unless `QJS_UPX` environment variable is set to `0`) 223 | 224 | # Nix 225 | 226 | In order to get a shell with interpreter (`qjs.sh`) and compiler (`qjsc.sh`), run following command 227 | 228 | ``` 229 | nix develop github:ctn-malone/quickjs-cross-compiler 230 | ``` 231 | 232 | Following commands can also be used to run `qjs.sh` or `qjsc.sh` using `nix run` 233 | 234 | - run `qjs.sh` 235 | 236 | ``` 237 | nix run github:ctn-malone/quickjs-cross-compiler 238 | ``` 239 | 240 | - run `qjsc.sh` 241 | 242 | ``` 243 | nix run github:ctn-malone/quickjs-cross-compiler#qjsc 244 | ``` 245 | 246 | # Embed custom javascript modules 247 | 248 | Starting from release `2020-11-08_2`, any javascript file placed alongside `qjs` & `qjsc` binaries can be referenced relatively from your main script. 249 | This allows to bundle adhoc packages containing javascript modules (argument parsing, ...) which can be shared across various scripts 250 | 251 | Example 252 | 253 | For a package containing an `ext` directory alongside `qjs` & `qjsc` binaries, file `ext/myExt.js` can be imported from any script using `import * as myExt from 'ext/myExt.js';` 254 | 255 | ``` 256 | . 257 | ├── [4.0K] examples 258 | ├── [4.0K] ext 259 | │   └── [ 335] myExt.js 260 | ├── [1.2M] libquickjs.a 261 | ├── [4.0K] musl-x86_64 262 | │   │   └... 263 | │   └── [4.0K] lib 264 | │   └... 265 | ├── [938K] qjs 266 | ├── [894K] qjsc 267 | ├── [ 364] qjsc.sh 268 | ├── [ 425] qjs.sh 269 | ├── [ 40K] quickjs.h 270 | └── [2.5K] quickjs-libc.h 271 | ``` 272 | 273 | *ext/myExt.js* 274 | ```javascript 275 | const sayHello = (name) => { 276 | console.log(`Hello ${name}`); 277 | } 278 | 279 | const WEEKDAYS = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday']; 280 | const sayWeekday = () => { 281 | const date = new Date(); 282 | const wday = WEEKDAYS[date.getDay()]; 283 | console.log(`Today is ${wday}`); 284 | } 285 | 286 | export default { 287 | sayHello:sayHello, 288 | sayWeekday:sayWeekday 289 | } 290 | export { sayHello, sayWeekday }; 291 | ``` 292 | 293 | *myScript.js* 294 | ```javascript 295 | import {sayHello, sayWeekday} from 'ext/myExt.js'; 296 | sayHello('John Doe'); 297 | sayWeekday(); 298 | ``` 299 | 300 | Both interpreter & compiler will first try to resolve import relatively to current directory and fallback to the directory containing `qjs` & `qjsc` binaries (or the directory defined using `QJS_LIB_DIR` environment variable) 301 | 302 | NB : fallback will only work when calling `qjs` & `qjsc` using their **absolute path** or through their corresponding **`sh` wrappers** 303 | 304 | Directories can be added to the package using argument `(--extra-dir, -e)` when calling `build_and_export_qjs.sh` script 305 | 306 | Examples 307 | 308 | ``` 309 | ./builder/build_and_export_qjs.sh -e /tmp/ext1 -e /tmp/ext2 310 | ``` 311 | 312 | Above command will copy `/tmp/ext1` & `/tmp/ext2` directories at the root of the package 313 | 314 | ``` 315 | ./builder/build_and_export_qjs.sh -e /tmp/ext1:ext -e /tmp/ext2:ext 316 | ``` 317 | 318 | Above command will copy **the content** of `/tmp/ext1` & `/tmp/ext2` directories into an `ext` subdirectory at the root of the package 319 | 320 | # Embed QuickJS extension library 321 | 322 | When using flag `--ext-lib`, [QuickJS extension library](https://github.com/ctn-malone/qjs-ext-lib) will be added to the package under `ext` directory 323 | 324 | This library contains a set of JS module to make creating static adhoc scripts easier 325 | 326 | # Limitations 327 | 328 | *QuickJS* is built without *LTO* support since `-flto` flag does not work when the host running `qjsc` is not using the same *gcc* bytecode version as the one used by the host where `qjsc` was compiled, resulting in a message such as below 329 | 330 | ``` 331 | lto1: fatal error: bytecode stream in file ‘/usr/local/bin/quickjs/libquickjs.lto.a’ generated with LTO version 7.1 instead of the expected 6.0 332 | ``` 333 | -------------------------------------------------------------------------------- /builder/build_and_export_qjs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### 4 | # 5 | # Build a static version of QuickJS (interpreter & compiler) 6 | # Export a portable package which can be used to generate static binaries 7 | # 8 | ### 9 | 10 | script_dir="$(cd "$(dirname "$(readlink -f "$0")")" && pwd)" || { echo "Couldn't determine the script's running directory, which probably matters, bailing out" >&2; exit 2; } 11 | source "${script_dir}/env/qjs" 12 | 13 | # Created by argbash-init v2.10.0 14 | # ARG_OPTIONAL_SINGLE([packages-dir],[p],[directory where package will be exported],[$script_dir/../packages]) 15 | # ARG_OPTIONAL_SINGLE([deps-dir],[],[directory where dependencies should be stored/buil],[$script_dir/../deps]) 16 | # ARG_OPTIONAL_SINGLE([arch],[a],[target architecture],[x86_64]) 17 | # ARG_OPTIONAL_BOOLEAN([ext-lib],[],[add QuickJS extension library],[off]) 18 | # ARG_OPTIONAL_SINGLE([ext-lib-version],[],[QuickJS extension library version],[$default_qjs_ext_lib_version]) 19 | # ARG_OPTIONAL_REPEATED([extra-dir],[e],[extra directory to add into package],[]) 20 | # ARG_OPTIONAL_BOOLEAN([force-fetch-deps],[],[force re-fetching dependencies],[off]) 21 | # ARG_OPTIONAL_BOOLEAN([force-build-deps],[],[force rebuild of dependencies],[off]) 22 | # ARG_OPTIONAL_BOOLEAN([force-checkout-qjs],[],[clone repository even if it exists],[off]) 23 | # ARG_OPTIONAL_BOOLEAN([force-build-qjs],[],[force rebuild of QuickJS],[off]) 24 | # ARG_OPTIONAL_BOOLEAN([verbose],[v],[enable verbose mode],[off]) 25 | # ARG_OPTIONAL_BOOLEAN([upx],[u],[compress binaries using upx],[on]) 26 | # ARG_POSITIONAL_SINGLE([qjs-version],[QuickJS version (ex: 2020-09-06)],[$default_qjs_version]) 27 | # ARG_TYPE_GROUP_SET([arch],[type string],[arch],[x86_64,i686,armv7l,aarch64]) 28 | # ARG_HELP([Build a static version of QuickJS (interpreter & compiler)]) 29 | # ARGBASH_GO() 30 | # needed because of Argbash --> m4_ignore([ 31 | ### START OF CODE GENERATED BY Argbash v2.10.0 one line above ### 32 | # Argbash is a bash code generator used to get arguments parsing right. 33 | # Argbash is FREE SOFTWARE, see https://argbash.io for more info 34 | 35 | 36 | die() 37 | { 38 | local _ret="${2:-1}" 39 | test "${_PRINT_HELP:-no}" = yes && print_help >&2 40 | echo "$1" >&2 41 | exit "${_ret}" 42 | } 43 | 44 | # validators 45 | 46 | arch() 47 | { 48 | local _allowed=("x86_64" "i686" "armv7l" "aarch64") _seeking="$1" 49 | for element in "${_allowed[@]}" 50 | do 51 | test "$element" = "$_seeking" && echo "$element" && return 0 52 | done 53 | die "Value '$_seeking' (of argument '$2') doesn't match the list of allowed values: 'x86_64', 'i686', 'armv7l' and 'aarch64'" 4 54 | } 55 | 56 | 57 | begins_with_short_option() 58 | { 59 | local first_option all_short_options='paevuh' 60 | first_option="${1:0:1}" 61 | test "$all_short_options" = "${all_short_options/$first_option/}" && return 1 || return 0 62 | } 63 | 64 | # THE DEFAULTS INITIALIZATION - POSITIONALS 65 | _positionals=() 66 | _arg_qjs_version="$default_qjs_version" 67 | # THE DEFAULTS INITIALIZATION - OPTIONALS 68 | _arg_packages_dir="$script_dir/../packages" 69 | _arg_deps_dir="$script_dir/../deps" 70 | _arg_arch="x86_64" 71 | _arg_ext_lib="off" 72 | _arg_ext_lib_version="$default_qjs_ext_lib_version" 73 | _arg_extra_dir=() 74 | _arg_force_fetch_deps="off" 75 | _arg_force_build_deps="off" 76 | _arg_force_checkout_qjs="off" 77 | _arg_force_build_qjs="off" 78 | _arg_verbose="off" 79 | _arg_upx="on" 80 | 81 | 82 | print_help() 83 | { 84 | printf '%s\n' "Build a static version of QuickJS (interpreter & compiler)" 85 | printf 'Usage: %s [-p|--packages-dir ] [--deps-dir ] [-a|--arch ] [--(no-)ext-lib] [--ext-lib-version ] [-e|--extra-dir ] [--(no-)force-fetch-deps] [--(no-)force-build-deps] [--(no-)force-checkout-qjs] [--(no-)force-build-qjs] [-v|--(no-)verbose] [-u|--(no-)upx] [-h|--help] []\n' "$0" 86 | printf '\t%s\n' ": QuickJS version (ex: 2020-09-06) (default: '$default_qjs_version')" 87 | printf '\t%s\n' "-p, --packages-dir: directory where package will be exported (default: '$script_dir/../packages')" 88 | printf '\t%s\n' "--deps-dir: directory where dependencies should be stored/buil (default: '$script_dir/../deps')" 89 | printf '\t%s\n' "-a, --arch: target architecture. Can be one of: 'x86_64', 'i686', 'armv7l' and 'aarch64' (default: 'x86_64')" 90 | printf '\t%s\n' "--ext-lib, --no-ext-lib: add QuickJS extension library (off by default)" 91 | printf '\t%s\n' "--ext-lib-version: QuickJS extension library version (default: '$default_qjs_ext_lib_version')" 92 | printf '\t%s\n' "-e, --extra-dir: extra directory to add into package (empty by default)" 93 | printf '\t%s\n' "--force-fetch-deps, --no-force-fetch-deps: force re-fetching dependencies (off by default)" 94 | printf '\t%s\n' "--force-build-deps, --no-force-build-deps: force rebuild of dependencies (off by default)" 95 | printf '\t%s\n' "--force-checkout-qjs, --no-force-checkout-qjs: clone repository even if it exists (off by default)" 96 | printf '\t%s\n' "--force-build-qjs, --no-force-build-qjs: force rebuild of QuickJS (off by default)" 97 | printf '\t%s\n' "-v, --verbose, --no-verbose: enable verbose mode (off by default)" 98 | printf '\t%s\n' "-u, --upx, --no-upx: compress binaries using upx (on by default)" 99 | printf '\t%s\n' "-h, --help: Prints help" 100 | } 101 | 102 | 103 | parse_commandline() 104 | { 105 | _positionals_count=0 106 | while test $# -gt 0 107 | do 108 | _key="$1" 109 | case "$_key" in 110 | -p|--packages-dir) 111 | test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 112 | _arg_packages_dir="$2" 113 | shift 114 | ;; 115 | --packages-dir=*) 116 | _arg_packages_dir="${_key##--packages-dir=}" 117 | ;; 118 | -p*) 119 | _arg_packages_dir="${_key##-p}" 120 | ;; 121 | --deps-dir) 122 | test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 123 | _arg_deps_dir="$2" 124 | shift 125 | ;; 126 | --deps-dir=*) 127 | _arg_deps_dir="${_key##--deps-dir=}" 128 | ;; 129 | -a|--arch) 130 | test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 131 | _arg_arch="$(arch "$2" "arch")" || exit 1 132 | shift 133 | ;; 134 | --arch=*) 135 | _arg_arch="$(arch "${_key##--arch=}" "arch")" || exit 1 136 | ;; 137 | -a*) 138 | _arg_arch="$(arch "${_key##-a}" "arch")" || exit 1 139 | ;; 140 | --no-ext-lib|--ext-lib) 141 | _arg_ext_lib="on" 142 | test "${1:0:5}" = "--no-" && _arg_ext_lib="off" 143 | ;; 144 | --ext-lib-version) 145 | test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 146 | _arg_ext_lib_version="$2" 147 | shift 148 | ;; 149 | --ext-lib-version=*) 150 | _arg_ext_lib_version="${_key##--ext-lib-version=}" 151 | ;; 152 | -e|--extra-dir) 153 | test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 154 | _arg_extra_dir+=("$2") 155 | shift 156 | ;; 157 | --extra-dir=*) 158 | _arg_extra_dir+=("${_key##--extra-dir=}") 159 | ;; 160 | -e*) 161 | _arg_extra_dir+=("${_key##-e}") 162 | ;; 163 | --no-force-fetch-deps|--force-fetch-deps) 164 | _arg_force_fetch_deps="on" 165 | test "${1:0:5}" = "--no-" && _arg_force_fetch_deps="off" 166 | ;; 167 | --no-force-build-deps|--force-build-deps) 168 | _arg_force_build_deps="on" 169 | test "${1:0:5}" = "--no-" && _arg_force_build_deps="off" 170 | ;; 171 | --no-force-checkout-qjs|--force-checkout-qjs) 172 | _arg_force_checkout_qjs="on" 173 | test "${1:0:5}" = "--no-" && _arg_force_checkout_qjs="off" 174 | ;; 175 | --no-force-build-qjs|--force-build-qjs) 176 | _arg_force_build_qjs="on" 177 | test "${1:0:5}" = "--no-" && _arg_force_build_qjs="off" 178 | ;; 179 | -v|--no-verbose|--verbose) 180 | _arg_verbose="on" 181 | test "${1:0:5}" = "--no-" && _arg_verbose="off" 182 | ;; 183 | -v*) 184 | _arg_verbose="on" 185 | _next="${_key##-v}" 186 | if test -n "$_next" -a "$_next" != "$_key" 187 | then 188 | { begins_with_short_option "$_next" && shift && set -- "-v" "-${_next}" "$@"; } || die "The short option '$_key' can't be decomposed to ${_key:0:2} and -${_key:2}, because ${_key:0:2} doesn't accept value and '-${_key:2:1}' doesn't correspond to a short option." 189 | fi 190 | ;; 191 | -u|--no-upx|--upx) 192 | _arg_upx="on" 193 | test "${1:0:5}" = "--no-" && _arg_upx="off" 194 | ;; 195 | -u*) 196 | _arg_upx="on" 197 | _next="${_key##-u}" 198 | if test -n "$_next" -a "$_next" != "$_key" 199 | then 200 | { begins_with_short_option "$_next" && shift && set -- "-u" "-${_next}" "$@"; } || die "The short option '$_key' can't be decomposed to ${_key:0:2} and -${_key:2}, because ${_key:0:2} doesn't accept value and '-${_key:2:1}' doesn't correspond to a short option." 201 | fi 202 | ;; 203 | -h|--help) 204 | print_help 205 | exit 0 206 | ;; 207 | -h*) 208 | print_help 209 | exit 0 210 | ;; 211 | *) 212 | _last_positional="$1" 213 | _positionals+=("$_last_positional") 214 | _positionals_count=$((_positionals_count + 1)) 215 | ;; 216 | esac 217 | shift 218 | done 219 | } 220 | 221 | 222 | handle_passed_args_count() 223 | { 224 | test "${_positionals_count}" -le 1 || _PRINT_HELP=yes die "FATAL ERROR: There were spurious positional arguments --- we expect between 0 and 1, but got ${_positionals_count} (the last one was: '${_last_positional}')." 1 225 | } 226 | 227 | 228 | assign_positional_args() 229 | { 230 | local _positional_name _shift_for=$1 231 | _positional_names="_arg_qjs_version " 232 | 233 | shift "$_shift_for" 234 | for _positional_name in ${_positional_names} 235 | do 236 | test $# -gt 0 || break 237 | eval "$_positional_name=\${1}" || die "Error during argument parsing, possibly an Argbash bug." 1 238 | shift 239 | done 240 | } 241 | 242 | parse_commandline "$@" 243 | handle_passed_args_count 244 | assign_positional_args 1 "${_positionals[@]}" 245 | 246 | # OTHER STUFF GENERATED BY Argbash 247 | # Validation of values 248 | 249 | 250 | ### END OF CODE GENERATED BY Argbash (sortof) ### ]) 251 | # [ <-- needed because of Argbash 252 | 253 | 254 | # vvv PLACE YOUR CODE HERE vvv 255 | 256 | source "${script_dir}/env/qjs" 257 | 258 | # ensure version exist 259 | qjs_commit="${qjs_commits[${_arg_qjs_version}]}" 260 | if [ -z ${qjs_commit} ] 261 | then 262 | _PRINT_HELP=yes die "QuickJS version '${_arg_qjs_version}' is not supported" 263 | fi 264 | 265 | _PRINT_HELP=no 266 | 267 | build_qjs() 268 | { 269 | _flag_verbose="" 270 | [ ${_arg_verbose} == "on" ] && _flag_verbose="-v" 271 | _flag_force_fetch_deps="" 272 | [ ${_arg_force_fetch_deps} == "on" ] && _flag_force_fetch_deps="-f" 273 | _flag_force_build_deps="" 274 | [ ${_arg_force_build_deps} == "on" ] && _flag_force_build_deps="-f" 275 | _flag_force_checkout_qjs="" 276 | [ ${_arg_force_checkout_qjs} == "on" ] && _flag_force_checkout_qjs="-f" 277 | _flag_force_build_qjs="" 278 | [ ${_arg_force_build_qjs} == "on" ] && _flag_force_build_qjs="-f" 279 | 280 | ${script_dir}/scripts/fetch_deps.sh ${_flag_verbose} -d ${_arg_deps_dir} -a ${_arg_arch} ${_flag_force_fetch_deps} || return 1 281 | ${script_dir}/scripts/build_deps.sh ${_flag_verbose} -d ${_arg_deps_dir} -a ${_arg_arch} ${_flag_force_build_deps} || return 1 282 | ${script_dir}/scripts/checkout_qjs.sh ${_arg_qjs_version} ${_flag_verbose} ${_flag_force_checkout_qjs} || return 1 283 | ${script_dir}/scripts/prepare_qjs.sh ${_arg_qjs_version} ${_flag_verbose} -d ${_arg_deps_dir} -a ${_arg_arch} || return 1 284 | ${script_dir}/scripts/build_qjs.sh ${_arg_qjs_version} ${_flag_verbose} -d ${_arg_deps_dir} -a ${_arg_arch} ${_flag_force_build_qjs} || return 1 285 | 286 | return 0 287 | } 288 | 289 | build_qjs || exit 1 290 | args_qjs_ext_lib="" 291 | if [ ${_arg_ext_lib} == "on" ] 292 | then 293 | args_qjs_ext_lib="--ext-lib --ext-lib-version ${_arg_ext_lib_version}" 294 | fi 295 | args_extra_dir="" 296 | for a in ${_arg_extra_dir[@]} 297 | do 298 | args_extra_dir="${args_extra_dir} -e ${a}" 299 | done 300 | _flag_disable_upx="" 301 | [ ${_arg_upx} == "off" ] && _flag_disable_upx="--no-upx" 302 | 303 | #echo "${script_dir}/scripts/export_qjs.sh ${_arg_qjs_version} ${_flag_verbose} -d ${_arg_deps_dir} -p ${_arg_packages_dir} -a ${_arg_arch} ${args_qjs_ext_lib} ${args_extra_dir} ${_flag_disable_upx}" 304 | ${script_dir}/scripts/export_qjs.sh ${_arg_qjs_version} ${_flag_verbose} -d ${_arg_deps_dir} -p ${_arg_packages_dir} -a ${_arg_arch} ${args_qjs_ext_lib} ${args_extra_dir} ${_flag_disable_upx} || exit 1 305 | 306 | echo "Successfully built & exported 'QuickJS' version '${_arg_qjs_version}' for '${_arg_arch}'" 307 | 308 | # ^^^ TERMINATE YOUR CODE BEFORE THE BOTTOM ARGBASH MARKER ^^^ 309 | 310 | # ] <-- needed because of Argbash 311 | -------------------------------------------------------------------------------- /builder/custom/README.md: -------------------------------------------------------------------------------- 1 | Cross compile [QuickJS](https://github.com/bellard/quickjs) interpreter & compiler statically. Resulting [QuickJS](https://github.com/bellard/quickjs) compiler also generates *static* binaries based on [musl libc](https://musl.libc.org/) 2 | 3 | Following target architectures are supported 4 | 5 | * x86_64 6 | * i686 7 | * armv7l 8 | * aarch64 9 | 10 | Cross compilation is performed using [musl.cc](https://musl.cc/) static compilers (which means you should be able to generate a portable package of *QuickJS* from any recent *x86_64* Linux distribution with *gcc*) 11 | 12 | Final portable version should weight around 7MB (after decompression) 13 | 14 | Static compiler should work with any Linux distribution with *gcc* >= `4.3.2` 15 | 16 | See https://github.com/ctn-malone/quickjs-cross-compiler for more informations 17 | -------------------------------------------------------------------------------- /builder/custom/musl/bin/musl-gcc: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ### 4 | # 5 | # Wrapper used to link to the musl library embedded in the portable package 6 | # Environment variable 'qjs_cc' will be used only when compiling QuickJS 7 | # 8 | ### 9 | 10 | script_dir="$( cd "$( dirname "${0}" )" >/dev/null && pwd )" 11 | 12 | # $1 version to check 13 | # $2 minimum version 14 | gte_version() 15 | { 16 | _major=$(echo $1 | cut -d'.' -f1) 17 | _major_minimum=$(echo $2 | cut -d'.' -f1) 18 | _minor=$(echo $1 | cut -s -d'.' -f2) 19 | [ -z ${_minor} ] && _minor=0 20 | _minor_minimum=$(echo $2 | cut -s -d'.' -f2) 21 | [ -z ${_minor_minimum} ] && _minor_minimum=0 22 | [ ${_major} -lt ${_major_minimum} ] && return 1 23 | [ ${_major} -gt ${_major_minimum} ] && return 0 24 | [ ${_minor} -lt ${_minor_minimum} ] && return 1 25 | return 0 26 | } 27 | 28 | musl_dir="${script_dir}/.." 29 | gcc_version=$(gcc -dumpversion) 30 | # extra gcc flags 31 | flags="" 32 | 33 | # only define new flags if ${qjs_cc} is not set (ie: if we're not building qjs) 34 | if [ -z ${qjs_cc} ] 35 | then 36 | # '-no-pie' flag is supported for gcc >= 6.1 37 | if gte_version ${gcc_version} "6.1" 38 | then 39 | flags="${flags} -no-pie" 40 | fi 41 | fi 42 | 43 | #echo "musl_dir=${musl_dir} exec \"${qjs_cc:-gcc}\" \"$@\" ${flags} -specs \"${musl_dir}/lib/musl-gcc.specs\"" 44 | musl_dir=${musl_dir} exec "${qjs_cc:-gcc}" "$@" ${flags} -specs "${musl_dir}/lib/musl-gcc.specs" 45 | -------------------------------------------------------------------------------- /builder/custom/musl/lib/musl-gcc.specs: -------------------------------------------------------------------------------- 1 | %rename cpp_options old_cpp_options 2 | 3 | *cpp_options: 4 | -nostdinc -isystem %:getenv(musl_dir /include) -isystem include%s %(old_cpp_options) 5 | 6 | *cc1: 7 | %(cc1_cpu) -nostdinc -isystem %:getenv(musl_dir /include) -isystem include%s 8 | 9 | *link_libgcc: 10 | -L %:getenv(musl_dir /lib) -L .%s 11 | 12 | *libgcc: 13 | libgcc.a%s %:if-exists(libgcc_eh.a%s) 14 | 15 | *startfile: 16 | %{!shared: %:getenv(musl_dir /lib/Scrt1.o)} %:getenv(musl_dir /lib/crti.o) crtbeginS.o%s 17 | 18 | *endfile: 19 | crtendS.o%s %:getenv(musl_dir /lib/crtn.o) 20 | 21 | *link: 22 | -dynamic-linker %:getenv(musl_dir /lib/ld-musl-x86_64.so.1) -nostdlib %{shared:-shared} %{static:-static} %{rdynamic:-export-dynamic} 23 | 24 | *esp_link: 25 | 26 | 27 | *esp_options: 28 | 29 | 30 | *esp_cpp_options: 31 | 32 | 33 | # comment to avoid gcc error "gcc: fatal error: specs file malformed after ..." 34 | # we need to have 2 lines after esp_cpp_options 35 | -------------------------------------------------------------------------------- /builder/custom/qjs/examples/ext-lib/example1.js: -------------------------------------------------------------------------------- 1 | import { exec } from 'ext/process.js'; 2 | 3 | /* 4 | Run 3 external commands in parallel 5 | */ 6 | 7 | const main = async () => { 8 | const commands = [ 9 | 'date', 10 | 'uptime', 11 | 'which sh' 12 | ]; 13 | const promises = []; 14 | commands.forEach(c => promises.push(exec(c))); 15 | (await Promise.all(promises)).forEach((output, i) => { 16 | console.log(`${commands[i]} => ${output}`); 17 | }); 18 | } 19 | 20 | main(); 21 | -------------------------------------------------------------------------------- /builder/custom/qjs/examples/ext-lib/example2.js: -------------------------------------------------------------------------------- 1 | import arg from 'ext/arg.js'; 2 | import * as path from 'ext/path.js'; 3 | import { exec } from 'ext/process.js'; 4 | 5 | import * as std from 'std'; 6 | 7 | /* 8 | Simple CLI example 9 | */ 10 | 11 | const COMMANDS = ['date', 'uptime']; 12 | 13 | const getUsage = () => { 14 | const message = ` 15 | Usage: ${path.getScriptName(true)} [-h|--help] [-c|--command] [-v|--verbose] 16 | -c --command: run command 17 | Should be one of [${COMMANDS.join(',')}] 18 | -v --verbose: enable verbose mode 19 | -h, --help: print help 20 | `.trim(); 21 | return message; 22 | } 23 | 24 | const getHelp = () => { 25 | const message = ` 26 | Run a command 27 | `.trim(); 28 | return `${message}\n${getUsage()}`; 29 | } 30 | 31 | let args; 32 | try { 33 | args = arg({ 34 | '--command': (v, n, p) => { 35 | const value = v.trim(); 36 | if (!COMMANDS.includes(value)) { 37 | const err = new Error(`Invalid option value: ${n} (${v}) (should be one of [${COMMANDS.join(',')}])`); 38 | err.code = 'ARG_INVALID_OPTION'; 39 | throw err; 40 | } 41 | return value; 42 | }, 43 | '--help': Boolean, 44 | '--verbose':Boolean, 45 | // aliases 46 | '-c': '--command', 47 | '-v': '--verbose', 48 | '-h': '--help' 49 | }); 50 | } 51 | catch (e) { 52 | switch (e.code) { 53 | case 'ARG_UNKNOWN_OPTION': 54 | case 'ARG_INVALID_OPTION': 55 | case 'ARG_MISSING_REQUIRED_SHORTARG': 56 | case 'ARG_MISSING_REQUIRED_LONGARG': 57 | std.err.printf(`${e.message.trim()}\n`); 58 | std.err.printf(`${getUsage()}\n`); 59 | std.exit(2); 60 | } 61 | throw e; 62 | } 63 | if (args['--help']) { 64 | std.err.printf(`${getHelp()}\n`); 65 | std.exit(2); 66 | } 67 | 68 | // ensure all required arguments were provided 69 | ['--command'].forEach((n) => { 70 | if (undefined === args[n]) { 71 | std.err.printf(`Option ${n} is required\n`); 72 | std.err.printf(`${getUsage()}\n`); 73 | std.exit(2); 74 | } 75 | }); 76 | 77 | if (args['--verbose']) { 78 | console.log(`Will run command '${args['--command']}'`); 79 | } 80 | exec(args['--command']).then((output) => { 81 | console.log(output); 82 | }); 83 | -------------------------------------------------------------------------------- /builder/custom/qjs/examples/ext-lib/example3.js: -------------------------------------------------------------------------------- 1 | import { curlRequest } from 'ext/curl.js'; 2 | 3 | /* 4 | Perform a POST request to https://jsonplaceholder.typicode.com/posts and print response payload 5 | */ 6 | 7 | const main = async () => { 8 | const body = await curlRequest('https://jsonplaceholder.typicode.com/posts', { 9 | method:'post', 10 | json: { 11 | title: 'foo', 12 | body: 'bar', 13 | userId: 1 14 | } 15 | }); 16 | console.log(JSON.stringify(body, null, 4)); 17 | } 18 | 19 | main(); 20 | -------------------------------------------------------------------------------- /builder/custom/qjs/examples/ext-lib/example4.js: -------------------------------------------------------------------------------- 1 | import { sshExec } from 'ext/ssh.js'; 2 | import * as std from 'std'; 3 | 4 | /* 5 | Execute 'date' command over ssh on localhost 6 | */ 7 | 8 | const main = async () => { 9 | try { 10 | const stdout = await sshExec('127.0.0.1', 'date'); 11 | console.log(`Date: ${stdout}`); 12 | } 13 | catch (e) { 14 | if (undefined !== e.sshErrorReason) { 15 | console.log(`SSH failed (${e.sshErrorReason}) : ${e.sshError}`); 16 | } 17 | else { 18 | console.log(`SSH failed : ${e.message}`); 19 | } 20 | std.exit(1); 21 | } 22 | } 23 | 24 | main(); 25 | -------------------------------------------------------------------------------- /builder/custom/qjs/files/path.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "path.h" 5 | 6 | static char exe_dir[4096]; 7 | 8 | /** 9 | * Build an absolute path by concatenating {dir} and a relative path 10 | * 11 | * @param {char*} buf buffer to update 12 | * @param {int} buf_size size of buffer 13 | * @param {char*} dir directory to concatenate 14 | * @param {char*} path path to concatenate 15 | */ 16 | void get_path_with_dir(char *buf, int buf_size, char* dir, char* path) 17 | { 18 | // only use {dir} if it exists and path is relative 19 | if (NULL != dir && NULL != path && '/' != path[0]) { 20 | pstrcpy(buf, buf_size, dir); 21 | pstrcat(buf, buf_size, "/"); 22 | } 23 | pstrcat(buf, buf_size, path); 24 | } 25 | 26 | /** 27 | * Update {exe_dir} variable based on executable name 28 | * 29 | * @param {char*} exe_name executable name 30 | */ 31 | void set_exe_dir_from_exe_name(char* exe_name) 32 | { 33 | char *p; 34 | /* get the directory of the executable */ 35 | pstrcpy(exe_dir, sizeof(exe_dir), exe_name); 36 | p = strrchr(exe_dir, '/'); 37 | if (p) { 38 | *p = '\0'; 39 | } else { 40 | pstrcpy(exe_dir, sizeof(exe_dir), "."); 41 | } 42 | } 43 | 44 | /** 45 | * Build an absolute path by concatenating {exe_dir} and a relative path 46 | * 47 | * @param {char*} buf buffer to update 48 | * @param {int} buf_size size of buffer 49 | * @param {char*} path path to concatenate 50 | */ 51 | void get_path_with_exe_dir(char *buf, int buf_size, char* path) 52 | { 53 | get_path_with_dir(buf, buf_size, exe_dir, path); 54 | } 55 | 56 | -------------------------------------------------------------------------------- /builder/custom/qjs/files/path.h: -------------------------------------------------------------------------------- 1 | #ifndef PATH_H 2 | #define PATH_H 3 | 4 | #include "cutils.h" 5 | 6 | void get_path_with_dir(char *buf, int buf_size, char* dir, char* path); 7 | void set_exe_dir_from_exe_name(char* exe_name); 8 | void get_path_with_exe_dir(char *buf, int buf_size, char* path); 9 | 10 | #endif /* PATH_H */ 11 | -------------------------------------------------------------------------------- /builder/custom/qjs/patches/2020-09-06/Makefile.patch: -------------------------------------------------------------------------------- 1 | diff --git a/Makefile b/Makefile 2 | index 94c8e31..faf35d4 100644 3 | --- a/Makefile 4 | +++ b/Makefile 5 | @@ -28,7 +28,8 @@ endif 6 | # Windows cross compilation from Linux 7 | #CONFIG_WIN32=y 8 | # use link time optimization (smaller and faster executables but slower build) 9 | -CONFIG_LTO=y 10 | +#-- disable LTO 11 | +#CONFIG_LTO=y 12 | # consider warnings as errors (for development) 13 | #CONFIG_WERROR=y 14 | # force 32 bit build for some utilities 15 | @@ -41,7 +42,9 @@ CONFIG_DEFAULT_AR=y 16 | endif 17 | 18 | # installation directory 19 | -prefix=/usr/local 20 | +#-- change prefix to / 21 | +#prefix=/usr/local 22 | +prefix=/ 23 | 24 | # use the gprof profiler 25 | #CONFIG_PROFILE=y 26 | @@ -82,7 +85,9 @@ ifdef CONFIG_CLANG 27 | endif 28 | else 29 | HOST_CC=gcc 30 | - CC=$(CROSS_PREFIX)gcc 31 | + #-- use musl-gcc instead of gcc (symlink must exist) 32 | + #CC=$(CROSS_PREFIX)gcc 33 | + CC=$(CURDIR)/musl-$(musl_arch)/bin/musl-gcc 34 | CFLAGS=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d 35 | CFLAGS += -Wno-array-bounds -Wno-format-truncation 36 | ifdef CONFIG_LTO 37 | @@ -96,6 +101,8 @@ ifdef CONFIG_WERROR 38 | CFLAGS+=-Werror 39 | endif 40 | DEFINES:=-D_GNU_SOURCE -DCONFIG_VERSION=\"$(shell cat VERSION)\" 41 | +#-- define target architecture 42 | +DEFINES+=-DMUSL_ARCH=\"$(musl_arch)\" 43 | ifdef CONFIG_BIGNUM 44 | DEFINES+=-DCONFIG_BIGNUM 45 | endif 46 | @@ -109,6 +116,10 @@ CFLAGS_SMALL=$(CFLAGS) -Os 47 | CFLAGS_OPT=$(CFLAGS) -O2 48 | CFLAGS_NOLTO:=$(CFLAGS_OPT) 49 | LDFLAGS=-g 50 | +#-- force static compilation 51 | +LDFLAGS+=-static 52 | +#-- disable PIE 53 | +CFLAGS+=-no-pie 54 | ifdef CONFIG_LTO 55 | CFLAGS_SMALL+=-flto 56 | CFLAGS_OPT+=-flto 57 | @@ -148,12 +159,17 @@ ifdef CONFIG_LTO 58 | PROGS+=libquickjs.lto.a 59 | endif 60 | 61 | +#--when architecture is not 'x86_64', we need to use the 'x86_64' version of the 'qjsc' binary to generate c files 62 | +QJSC_X86_64=$(qjsc_binary) 63 | + 64 | # examples 65 | ifeq ($(CROSS_PREFIX),) 66 | ifdef CONFIG_ASAN 67 | PROGS+= 68 | else 69 | -PROGS+=examples/hello examples/hello_module examples/test_fib 70 | +#-- disable 'hello_module' & 'test_fib' examples because of cross-compilation 71 | +#PROGS+=examples/hello examples/hello_module examples/test_fib 72 | +PROGS+=examples/hello 73 | ifndef CONFIG_DARWIN 74 | PROGS+=examples/fib.so examples/point.so 75 | endif 76 | @@ -176,6 +192,9 @@ ifndef CONFIG_WIN32 77 | LIBS+=-ldl -lpthread 78 | endif 79 | 80 | +#-- static linking to libatomic (necessary for armv7l) 81 | +LIBS+=-L $(CURDIR)/musl-$(musl_arch)/lib -latomic 82 | + 83 | $(OBJDIR): 84 | mkdir -p $(OBJDIR) $(OBJDIR)/examples $(OBJDIR)/tests 85 | 86 | @@ -230,10 +249,12 @@ libquickjs.a: $(patsubst %.o, %.nolto.o, $(QJS_LIB_OBJS)) 87 | endif # CONFIG_LTO 88 | 89 | repl.c: $(QJSC) repl.js 90 | - $(QJSC) -c -o $@ -m repl.js 91 | + #-- will use the 'x86_64' version of 'qjsc' when architecture is not 'x86_64' 92 | + $(QJSC_X86_64) -c -o $@ -m repl.js 93 | 94 | qjscalc.c: $(QJSC) qjscalc.js 95 | - $(QJSC) -fbignum -c -o $@ qjscalc.js 96 | + #-- will use the 'x86_64' version of 'qjsc' when architecture is not 'x86_64' 97 | + $(QJSC_X86_64) -fbignum -c -o $@ qjscalc.js 98 | 99 | ifneq ($(wildcard unicode/UnicodeData.txt),) 100 | $(OBJDIR)/libunicode.o $(OBJDIR)/libunicode.m32.o $(OBJDIR)/libunicode.m32s.o \ 101 | @@ -295,9 +316,12 @@ clean: 102 | rm -rf $(OBJDIR)/ *.dSYM/ qjs-debug 103 | rm -rf run-test262-debug run-test262-32 104 | 105 | -install: all 106 | +#-- only install 107 | +#install: all 108 | +install: 109 | mkdir -p "$(DESTDIR)$(prefix)/bin" 110 | - $(STRIP) qjs qjsc 111 | + #-- disable stripping (because of cross-compiling) 112 | + #$(STRIP) qjs qjsc 113 | install -m755 qjs qjsc "$(DESTDIR)$(prefix)/bin" 114 | ln -sf qjs "$(DESTDIR)$(prefix)/bin/qjscalc" 115 | mkdir -p "$(DESTDIR)$(prefix)/lib/quickjs" 116 | @@ -321,7 +345,8 @@ HELLO_OPTS+=-fno-bigint 117 | endif 118 | 119 | hello.c: $(QJSC) $(HELLO_SRCS) 120 | - $(QJSC) -e $(HELLO_OPTS) -o $@ $(HELLO_SRCS) 121 | + #-- will use the 'x86_64' version of 'qjsc' when architecture is not 'x86_64' 122 | + $(QJSC_X86_64) -e $(HELLO_OPTS) -o $@ $(HELLO_SRCS) 123 | 124 | ifdef CONFIG_M32 125 | examples/hello: $(OBJDIR)/hello.m32s.o $(patsubst %.o, %.m32s.o, $(QJS_LIB_OBJS)) 126 | -------------------------------------------------------------------------------- /builder/custom/qjs/patches/2020-09-06/qjsc.patch: -------------------------------------------------------------------------------- 1 | diff --git a/qjsc.c b/qjsc.c 2 | index f5bda57..7e1919d 100644 3 | --- a/qjsc.c 4 | +++ b/qjsc.c 5 | @@ -370,6 +370,13 @@ 6 | printf("]\n" 7 | " disable selected language features (smaller code size)\n"); 8 | } 9 | +#else 10 | + //-- define '-fbignum' if 'CONFIG_BIGNUM' is defined 11 | + #ifdef CONFIG_BIGNUM 12 | + { 13 | + printf("-fbignum enable bignum extensions\n"); 14 | + } 15 | + #endif 16 | #endif 17 | exit(1); 18 | } 19 | @@ -401,6 +408,8 @@ 20 | const char **arg, *bn_suffix, *lto_suffix; 21 | char libjsname[1024]; 22 | char exe_dir[1024], inc_dir[1024], lib_dir[1024], buf[1024], *p; 23 | + //-- used to store relative path to musl-gcc 24 | + char musl_gcc[1024]; 25 | int ret; 26 | 27 | /* get the directory of the executable */ 28 | @@ -427,8 +436,15 @@ 29 | bn_suffix = ""; 30 | 31 | arg = argv; 32 | - *arg++ = CONFIG_CC; 33 | + //-- use included musl-gcc wrapper instead of default compiler 34 | + //*arg++ = CONFIG_CC; 35 | + snprintf(musl_gcc, sizeof(musl_gcc), "%s/musl-%s/bin/musl-gcc", exe_dir, MUSL_ARCH); 36 | + *arg++ = musl_gcc; 37 | *arg++ = "-O2"; 38 | + //-- force static compilation 39 | + *arg++ = "-static"; 40 | + //-- strip 41 | + *arg++ = "-s"; 42 | #ifdef CONFIG_LTO 43 | if (use_lto) { 44 | *arg++ = "-flto"; 45 | @@ -452,6 +468,8 @@ 46 | *arg++ = "-lm"; 47 | *arg++ = "-ldl"; 48 | *arg++ = "-lpthread"; 49 | + //-- link to libatomic (armv7l) 50 | + *arg++ = "-latomic"; 51 | *arg = NULL; 52 | 53 | if (verbose) { 54 | 55 | -------------------------------------------------------------------------------- /builder/custom/qjs/patches/2020-11-08/Makefile.patch: -------------------------------------------------------------------------------- 1 | diff --git a/Makefile b/Makefile 2 | index e6ae827..e36b8c4 100644 3 | --- a/Makefile 4 | +++ b/Makefile 5 | @@ -28,7 +28,8 @@ endif 6 | # Windows cross compilation from Linux 7 | #CONFIG_WIN32=y 8 | # use link time optimization (smaller and faster executables but slower build) 9 | -CONFIG_LTO=y 10 | +#-- disable LTO 11 | +#CONFIG_LTO=y 12 | # consider warnings as errors (for development) 13 | #CONFIG_WERROR=y 14 | # force 32 bit build for some utilities 15 | @@ -41,7 +42,9 @@ CONFIG_DEFAULT_AR=y 16 | endif 17 | 18 | # installation directory 19 | -prefix=/usr/local 20 | +#-- change prefix to / 21 | +#prefix=/usr/local 22 | +prefix=/ 23 | 24 | # use the gprof profiler 25 | #CONFIG_PROFILE=y 26 | @@ -86,7 +89,9 @@ ifdef CONFIG_CLANG 27 | endif 28 | else 29 | HOST_CC=gcc 30 | - CC=$(CROSS_PREFIX)gcc 31 | + #-- use musl-gcc instead of gcc (symlink must exist) 32 | + #CC=$(CROSS_PREFIX)gcc 33 | + CC=$(CURDIR)/musl-$(musl_arch)/bin/musl-gcc 34 | CFLAGS=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d 35 | CFLAGS += -Wno-array-bounds -Wno-format-truncation 36 | ifdef CONFIG_LTO 37 | @@ -100,6 +105,8 @@ ifdef CONFIG_WERROR 38 | CFLAGS+=-Werror 39 | endif 40 | DEFINES:=-D_GNU_SOURCE -DCONFIG_VERSION=\"$(shell cat VERSION)\" 41 | +#-- define target architecture 42 | +DEFINES+=-DMUSL_ARCH=\"$(musl_arch)\" 43 | ifdef CONFIG_BIGNUM 44 | DEFINES+=-DCONFIG_BIGNUM 45 | endif 46 | @@ -113,6 +120,10 @@ CFLAGS_SMALL=$(CFLAGS) -Os 47 | CFLAGS_OPT=$(CFLAGS) -O2 48 | CFLAGS_NOLTO:=$(CFLAGS_OPT) 49 | LDFLAGS=-g 50 | +#-- force static compilation 51 | +LDFLAGS+=-static 52 | +#-- disable PIE 53 | +CFLAGS+=-no-pie 54 | ifdef CONFIG_LTO 55 | CFLAGS_SMALL+=-flto 56 | CFLAGS_OPT+=-flto 57 | @@ -152,12 +163,17 @@ ifdef CONFIG_LTO 58 | PROGS+=libquickjs.lto.a 59 | endif 60 | 61 | +#--when architecture is not 'x86_64', we need to use the 'x86_64' version of the 'qjsc' binary to generate c files 62 | +QJSC_X86_64=$(qjsc_binary) 63 | + 64 | # examples 65 | ifeq ($(CROSS_PREFIX),) 66 | ifdef CONFIG_ASAN 67 | PROGS+= 68 | else 69 | -PROGS+=examples/hello examples/hello_module examples/test_fib 70 | +#-- disable 'hello_module' & 'test_fib' examples because of cross-compilation 71 | +#PROGS+=examples/hello examples/hello_module examples/test_fib 72 | +PROGS+=examples/hello 73 | ifndef CONFIG_DARWIN 74 | PROGS+=examples/fib.so examples/point.so 75 | endif 76 | @@ -166,7 +182,7 @@ endif 77 | 78 | all: $(OBJDIR) $(OBJDIR)/quickjs.check.o $(OBJDIR)/qjs.check.o $(PROGS) 79 | 80 | -QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o 81 | +QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o $(OBJDIR)/path.o 82 | 83 | QJS_OBJS=$(OBJDIR)/qjs.o $(OBJDIR)/repl.o $(QJS_LIB_OBJS) 84 | ifdef CONFIG_BIGNUM 85 | @@ -180,6 +196,9 @@ ifndef CONFIG_WIN32 86 | LIBS+=-ldl -lpthread 87 | endif 88 | 89 | +#-- static linking to libatomic (necessary for armv7l) 90 | +LIBS+=-L $(CURDIR)/musl-$(musl_arch)/lib -latomic 91 | + 92 | $(OBJDIR): 93 | mkdir -p $(OBJDIR) $(OBJDIR)/examples $(OBJDIR)/tests 94 | 95 | @@ -234,10 +253,12 @@ libquickjs.a: $(patsubst %.o, %.nolto.o, $(QJS_LIB_OBJS)) 96 | endif # CONFIG_LTO 97 | 98 | repl.c: $(QJSC) repl.js 99 | - $(QJSC) -c -o $@ -m repl.js 100 | + #-- will use the 'x86_64' version of 'qjsc' when architecture is not 'x86_64' 101 | + $(QJSC_X86_64) -c -o $@ -m repl.js 102 | 103 | qjscalc.c: $(QJSC) qjscalc.js 104 | - $(QJSC) -fbignum -c -o $@ qjscalc.js 105 | + #-- will use the 'x86_64' version of 'qjsc' when architecture is not 'x86_64' 106 | + $(QJSC_X86_64) -fbignum -c -o $@ qjscalc.js 107 | 108 | ifneq ($(wildcard unicode/UnicodeData.txt),) 109 | $(OBJDIR)/libunicode.o $(OBJDIR)/libunicode.m32.o $(OBJDIR)/libunicode.m32s.o \ 110 | @@ -296,9 +317,12 @@ clean: 111 | rm -rf $(OBJDIR)/ *.dSYM/ qjs-debug 112 | rm -rf run-test262-debug run-test262-32 113 | 114 | -install: all 115 | +#-- only install 116 | +#install: all 117 | +install: 118 | mkdir -p "$(DESTDIR)$(prefix)/bin" 119 | - $(STRIP) qjs qjsc 120 | + #-- disable stripping (because of cross-compiling) 121 | + #$(STRIP) qjs qjsc 122 | install -m755 qjs qjsc "$(DESTDIR)$(prefix)/bin" 123 | ln -sf qjs "$(DESTDIR)$(prefix)/bin/qjscalc" 124 | mkdir -p "$(DESTDIR)$(prefix)/lib/quickjs" 125 | @@ -322,7 +346,8 @@ HELLO_OPTS+=-fno-bigint 126 | endif 127 | 128 | hello.c: $(QJSC) $(HELLO_SRCS) 129 | - $(QJSC) -e $(HELLO_OPTS) -o $@ $(HELLO_SRCS) 130 | + #-- will use the 'x86_64' version of 'qjsc' when architecture is not 'x86_64' 131 | + $(QJSC_X86_64) -e $(HELLO_OPTS) -o $@ $(HELLO_SRCS) 132 | 133 | ifdef CONFIG_M32 134 | examples/hello: $(OBJDIR)/hello.m32s.o $(patsubst %.o, %.m32s.o, $(QJS_LIB_OBJS)) 135 | -------------------------------------------------------------------------------- /builder/custom/qjs/patches/2020-11-08/qjs.patch: -------------------------------------------------------------------------------- 1 | diff --git a/qjs.c b/qjs.c 2 | index 4dd11f8..ae19184 100644 3 | --- a/qjs.c 4 | +++ b/qjs.c 5 | @@ -41,6 +41,8 @@ 6 | #include "cutils.h" 7 | #include "quickjs-libc.h" 8 | 9 | +#include "path.h" 10 | + 11 | extern const uint8_t qjsc_repl[]; 12 | extern const uint32_t qjsc_repl_size; 13 | #ifdef CONFIG_BIGNUM 14 | @@ -331,7 +333,9 @@ int main(int argc, char **argv) 15 | load_jscalc = !strcmp(exename, "qjscalc"); 16 | } 17 | #endif 18 | - 19 | + 20 | + set_exe_dir_from_exe_name(argv[0]); 21 | + 22 | /* cannot use getopt because we want to pass the command line to 23 | the script */ 24 | optind = 1; 25 | -------------------------------------------------------------------------------- /builder/custom/qjs/patches/2020-11-08/qjsc.patch: -------------------------------------------------------------------------------- 1 | diff --git a/qjsc.c b/qjsc.c 2 | index f5bda57..86db7fe 100644 3 | --- a/qjsc.c 4 | +++ b/qjsc.c 5 | @@ -1,6 +1,6 @@ 6 | /* 7 | * QuickJS command line compiler 8 | - * 9 | + * 10 | * Copyright (c) 2018-2020 Fabrice Bellard 11 | * 12 | * Permission is hereby granted, free of charge, to any person obtaining a copy 13 | @@ -36,6 +36,8 @@ 14 | #include "cutils.h" 15 | #include "quickjs-libc.h" 16 | 17 | +#include "path.h" 18 | + 19 | typedef struct { 20 | char *name; 21 | char *short_name; 22 | @@ -131,7 +133,7 @@ static void get_c_name(char *buf, size_t buf_size, const char *file) 23 | size_t len, i; 24 | int c; 25 | char *q; 26 | - 27 | + 28 | p = strrchr(file, '/'); 29 | if (!p) 30 | p = file; 31 | @@ -189,8 +191,8 @@ static void output_object_code(JSContext *ctx, 32 | } 33 | 34 | namelist_add(&cname_list, c_name, NULL, load_only); 35 | - 36 | - fprintf(fo, "const uint32_t %s_size = %u;\n\n", 37 | + 38 | + fprintf(fo, "const uint32_t %s_size = %u;\n\n", 39 | c_name, (unsigned int)out_buf_len); 40 | fprintf(fo, "const uint8_t %s[%u] = {\n", 41 | c_name, (unsigned int)out_buf_len); 42 | @@ -253,14 +255,27 @@ JSModuleDef *jsc_module_loader(JSContext *ctx, 43 | uint8_t *buf; 44 | JSValue func_val; 45 | char cname[1024]; 46 | - 47 | + 48 | buf = js_load_file(ctx, &buf_len, module_name); 49 | +/* 50 | if (!buf) { 51 | JS_ThrowReferenceError(ctx, "could not load module filename '%s'", 52 | module_name); 53 | return NULL; 54 | } 55 | - 56 | +*/ 57 | + if (!buf) { 58 | + // try with a path relative to qjsc exe 59 | + char path[4096]; 60 | + get_path_with_exe_dir(path, sizeof(path), (char*)module_name); 61 | + buf = js_load_file(ctx, &buf_len, path); 62 | + if (!buf) { 63 | + JS_ThrowReferenceError(ctx, "could not load module filename '%s'", 64 | + module_name); 65 | + return NULL; 66 | + } 67 | + } 68 | + 69 | /* compile the module */ 70 | func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name, 71 | JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY); 72 | @@ -272,7 +287,7 @@ JSModuleDef *jsc_module_loader(JSContext *ctx, 73 | find_unique_cname(cname, sizeof(cname)); 74 | } 75 | output_object_code(ctx, outfile, func_val, cname, TRUE); 76 | - 77 | + 78 | /* the module is already referenced, so we must free it */ 79 | m = JS_VALUE_GET_PTR(func_val); 80 | JS_FreeValue(ctx, func_val); 81 | @@ -290,7 +305,7 @@ static void compile_file(JSContext *ctx, FILE *fo, 82 | int eval_flags; 83 | JSValue obj; 84 | size_t buf_len; 85 | - 86 | + 87 | buf = js_load_file(ctx, &buf_len, filename); 88 | if (!buf) { 89 | fprintf(stderr, "Could not load '%s'\n", filename); 90 | @@ -370,6 +385,13 @@ void help(void) 91 | printf("]\n" 92 | " disable selected language features (smaller code size)\n"); 93 | } 94 | +#else 95 | + //-- define '-fbignum' if 'CONFIG_BIGNUM' is defined 96 | + #ifdef CONFIG_BIGNUM 97 | + { 98 | + printf("-fbignum enable bignum extensions\n"); 99 | + } 100 | + #endif 101 | #endif 102 | exit(1); 103 | } 104 | @@ -384,7 +406,7 @@ int exec_cmd(char **argv) 105 | if (pid == 0) { 106 | execvp(argv[0], argv); 107 | exit(1); 108 | - } 109 | + } 110 | 111 | for(;;) { 112 | ret = waitpid(pid, &status, 0); 113 | @@ -401,8 +423,10 @@ static int output_executable(const char *out_filename, const char *cfilename, 114 | const char **arg, *bn_suffix, *lto_suffix; 115 | char libjsname[1024]; 116 | char exe_dir[1024], inc_dir[1024], lib_dir[1024], buf[1024], *p; 117 | + //-- used to store relative path to musl-gcc 118 | + char musl_gcc[4096]; 119 | int ret; 120 | - 121 | + 122 | /* get the directory of the executable */ 123 | pstrcpy(exe_dir, sizeof(exe_dir), exename); 124 | p = strrchr(exe_dir, '/'); 125 | @@ -422,13 +446,20 @@ static int output_executable(const char *out_filename, const char *cfilename, 126 | snprintf(inc_dir, sizeof(inc_dir), "%s/include/quickjs", CONFIG_PREFIX); 127 | snprintf(lib_dir, sizeof(lib_dir), "%s/lib/quickjs", CONFIG_PREFIX); 128 | } 129 | - 130 | + 131 | lto_suffix = ""; 132 | bn_suffix = ""; 133 | - 134 | + 135 | arg = argv; 136 | - *arg++ = CONFIG_CC; 137 | + //-- use included musl-gcc wrapper instead of default compiler 138 | + //*arg++ = CONFIG_CC; 139 | + snprintf(musl_gcc, sizeof(musl_gcc), "%s/musl-%s/bin/musl-gcc", exe_dir, MUSL_ARCH); 140 | + *arg++ = musl_gcc; 141 | *arg++ = "-O2"; 142 | + //-- force static compilation 143 | + *arg++ = "-static"; 144 | + //-- strip 145 | + *arg++ = "-s"; 146 | #ifdef CONFIG_LTO 147 | if (use_lto) { 148 | *arg++ = "-flto"; 149 | @@ -452,14 +483,16 @@ static int output_executable(const char *out_filename, const char *cfilename, 150 | *arg++ = "-lm"; 151 | *arg++ = "-ldl"; 152 | *arg++ = "-lpthread"; 153 | + //-- link to libatomic (armv7l) 154 | + *arg++ = "-latomic"; 155 | *arg = NULL; 156 | - 157 | + 158 | if (verbose) { 159 | for(arg = argv; *arg != NULL; arg++) 160 | printf("%s ", *arg); 161 | printf("\n"); 162 | } 163 | - 164 | + 165 | ret = exec_cmd((char **)argv); 166 | unlink(cfilename); 167 | return ret; 168 | @@ -497,7 +530,7 @@ int main(int argc, char **argv) 169 | BOOL bignum_ext = FALSE; 170 | #endif 171 | namelist_t dynamic_module_list; 172 | - 173 | + 174 | out_filename = NULL; 175 | output_type = OUTPUT_EXECUTABLE; 176 | cname = NULL; 177 | @@ -508,11 +541,13 @@ int main(int argc, char **argv) 178 | use_lto = FALSE; 179 | stack_size = 0; 180 | memset(&dynamic_module_list, 0, sizeof(dynamic_module_list)); 181 | - 182 | + 183 | /* add system modules */ 184 | namelist_add(&cmodule_list, "std", "std", 0); 185 | namelist_add(&cmodule_list, "os", "os", 0); 186 | 187 | + set_exe_dir_from_exe_name(argv[0]); 188 | + 189 | for(;;) { 190 | c = getopt(argc, argv, "ho:cN:f:mxevM:p:S:D:"); 191 | if (c == -1) 192 | @@ -621,14 +656,14 @@ int main(int argc, char **argv) 193 | } else { 194 | pstrcpy(cfilename, sizeof(cfilename), out_filename); 195 | } 196 | - 197 | + 198 | fo = fopen(cfilename, "w"); 199 | if (!fo) { 200 | perror(cfilename); 201 | exit(1); 202 | } 203 | outfile = fo; 204 | - 205 | + 206 | rt = JS_NewRuntime(); 207 | ctx = JS_NewContext(rt); 208 | #ifdef CONFIG_BIGNUM 209 | @@ -639,14 +674,14 @@ int main(int argc, char **argv) 210 | JS_EnableBignumExt(ctx, TRUE); 211 | } 212 | #endif 213 | - 214 | + 215 | /* loader for ES6 modules */ 216 | JS_SetModuleLoaderFunc(rt, NULL, jsc_module_loader, NULL); 217 | 218 | fprintf(fo, "/* File generated automatically by the QuickJS compiler. */\n" 219 | "\n" 220 | ); 221 | - 222 | + 223 | if (output_type != OUTPUT_C) { 224 | fprintf(fo, "#include \"quickjs-libc.h\"\n" 225 | "\n" 226 | @@ -670,7 +705,7 @@ int main(int argc, char **argv) 227 | exit(1); 228 | } 229 | } 230 | - 231 | + 232 | if (output_type != OUTPUT_C) { 233 | fprintf(fo, 234 | "static JSContext *JS_NewCustomContext(JSRuntime *rt)\n" 235 | @@ -701,7 +736,7 @@ int main(int argc, char **argv) 236 | for(i = 0; i < init_module_list.count; i++) { 237 | namelist_entry_t *e = &init_module_list.array[i]; 238 | /* initialize the static C modules */ 239 | - 240 | + 241 | fprintf(fo, 242 | " {\n" 243 | " extern JSModuleDef *js_init_module_%s(JSContext *ctx, const char *name);\n" 244 | @@ -719,19 +754,19 @@ int main(int argc, char **argv) 245 | fprintf(fo, 246 | " return ctx;\n" 247 | "}\n\n"); 248 | - 249 | + 250 | fputs(main_c_template1, fo); 251 | 252 | if (stack_size != 0) { 253 | fprintf(fo, " JS_SetMaxStackSize(rt, %u);\n", 254 | (unsigned int)stack_size); 255 | } 256 | - 257 | + 258 | /* add the module loader if necessary */ 259 | if (feature_bitmap & (1 << FE_MODULE_LOADER)) { 260 | fprintf(fo, " JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);\n"); 261 | } 262 | - 263 | + 264 | fprintf(fo, 265 | " ctx = JS_NewCustomContext(rt);\n" 266 | " js_std_add_helpers(ctx, argc, argv);\n"); 267 | @@ -745,7 +780,7 @@ int main(int argc, char **argv) 268 | } 269 | fputs(main_c_template2, fo); 270 | } 271 | - 272 | + 273 | JS_FreeContext(ctx); 274 | JS_FreeRuntime(rt); 275 | 276 | -------------------------------------------------------------------------------- /builder/custom/qjs/patches/2020-11-08/quickjs-libc.patch: -------------------------------------------------------------------------------- 1 | diff --git a/quickjs-libc.c b/quickjs-libc.c 2 | index e8b81e9..946790e 100644 3 | --- a/quickjs-libc.c 4 | +++ b/quickjs-libc.c 5 | @@ -71,6 +71,8 @@ typedef sig_t sighandler_t; 6 | #include "list.h" 7 | #include "quickjs-libc.h" 8 | 9 | +#include "path.h" 10 | + 11 | /* TODO: 12 | - add socket calls 13 | */ 14 | @@ -577,11 +579,24 @@ JSModuleDef *js_module_loader(JSContext *ctx, 15 | JSValue func_val; 16 | 17 | buf = js_load_file(ctx, &buf_len, module_name); 18 | +/* 19 | if (!buf) { 20 | JS_ThrowReferenceError(ctx, "could not load module filename '%s'", 21 | module_name); 22 | return NULL; 23 | } 24 | +*/ 25 | + if (!buf) { 26 | + // try with a path relative to exe 27 | + char path[4096]; 28 | + get_path_with_exe_dir(path, sizeof(path), (char*)module_name); 29 | + buf = js_load_file(ctx, &buf_len, path); 30 | + if (!buf) { 31 | + JS_ThrowReferenceError(ctx, "could not load module filename '%s'", 32 | + module_name); 33 | + return NULL; 34 | + } 35 | + } 36 | 37 | /* compile the module */ 38 | func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name, 39 | -------------------------------------------------------------------------------- /builder/custom/qjs/patches/2021-03-27/Makefile.patch: -------------------------------------------------------------------------------- 1 | diff --git a/Makefile b/Makefile 2 | index 49b1f6f..9dc1097 100644 3 | --- a/Makefile 4 | +++ b/Makefile 5 | @@ -28,7 +28,8 @@ endif 6 | # Windows cross compilation from Linux 7 | #CONFIG_WIN32=y 8 | # use link time optimization (smaller and faster executables but slower build) 9 | -CONFIG_LTO=y 10 | +#-- disable LTO 11 | +#CONFIG_LTO=y 12 | # consider warnings as errors (for development) 13 | #CONFIG_WERROR=y 14 | # force 32 bit build for some utilities 15 | @@ -41,7 +42,9 @@ CONFIG_DEFAULT_AR=y 16 | endif 17 | 18 | # installation directory 19 | -prefix=/usr/local 20 | +#-- change prefix to / 21 | +#prefix=/usr/local 22 | +prefix=/ 23 | 24 | # use the gprof profiler 25 | #CONFIG_PROFILE=y 26 | @@ -86,7 +89,9 @@ ifdef CONFIG_CLANG 27 | endif 28 | else 29 | HOST_CC=gcc 30 | - CC=$(CROSS_PREFIX)gcc 31 | + #-- use musl-gcc instead of gcc (symlink must exist) 32 | + #CC=$(CROSS_PREFIX)gcc 33 | + CC=$(CURDIR)/musl-$(musl_arch)/bin/musl-gcc 34 | CFLAGS=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d 35 | CFLAGS += -Wno-array-bounds -Wno-format-truncation 36 | ifdef CONFIG_LTO 37 | @@ -100,6 +105,8 @@ ifdef CONFIG_WERROR 38 | CFLAGS+=-Werror 39 | endif 40 | DEFINES:=-D_GNU_SOURCE -DCONFIG_VERSION=\"$(shell cat VERSION)\" 41 | +#-- define target architecture 42 | +DEFINES+=-DMUSL_ARCH=\"$(musl_arch)\" 43 | ifdef CONFIG_BIGNUM 44 | DEFINES+=-DCONFIG_BIGNUM 45 | endif 46 | @@ -113,6 +120,10 @@ CFLAGS_SMALL=$(CFLAGS) -Os 47 | CFLAGS_OPT=$(CFLAGS) -O2 48 | CFLAGS_NOLTO:=$(CFLAGS_OPT) 49 | LDFLAGS=-g 50 | +#-- force static compilation 51 | +LDFLAGS+=-static 52 | +#-- disable PIE 53 | +CFLAGS+=-no-pie 54 | ifdef CONFIG_LTO 55 | CFLAGS_SMALL+=-flto 56 | CFLAGS_OPT+=-flto 57 | @@ -152,12 +163,17 @@ ifdef CONFIG_LTO 58 | PROGS+=libquickjs.lto.a 59 | endif 60 | 61 | +#--when architecture is not 'x86_64', we need to use the 'x86_64' version of the 'qjsc' binary to generate c files 62 | +QJSC_X86_64=$(qjsc_binary) 63 | + 64 | # examples 65 | ifeq ($(CROSS_PREFIX),) 66 | ifdef CONFIG_ASAN 67 | PROGS+= 68 | else 69 | -PROGS+=examples/hello examples/hello_module examples/test_fib 70 | +#-- disable 'hello_module' & 'test_fib' examples because of cross-compilation 71 | +#PROGS+=examples/hello examples/hello_module examples/test_fib 72 | +PROGS+=examples/hello 73 | ifndef CONFIG_DARWIN 74 | PROGS+=examples/fib.so examples/point.so 75 | endif 76 | @@ -166,7 +182,7 @@ endif 77 | 78 | all: $(OBJDIR) $(OBJDIR)/quickjs.check.o $(OBJDIR)/qjs.check.o $(PROGS) 79 | 80 | -QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o 81 | +QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o $(OBJDIR)/path.o 82 | 83 | QJS_OBJS=$(OBJDIR)/qjs.o $(OBJDIR)/repl.o $(QJS_LIB_OBJS) 84 | ifdef CONFIG_BIGNUM 85 | @@ -181,6 +197,9 @@ LIBS+=-ldl -lpthread 86 | endif 87 | LIBS+=$(EXTRA_LIBS) 88 | 89 | +#-- static linking to libatomic (necessary for armv7l) 90 | +LIBS+=-L $(CURDIR)/musl-$(musl_arch)/lib -latomic 91 | + 92 | $(OBJDIR): 93 | mkdir -p $(OBJDIR) $(OBJDIR)/examples $(OBJDIR)/tests 94 | 95 | @@ -235,10 +254,12 @@ libquickjs.a: $(patsubst %.o, %.nolto.o, $(QJS_LIB_OBJS)) 96 | endif # CONFIG_LTO 97 | 98 | repl.c: $(QJSC) repl.js 99 | - $(QJSC) -c -o $@ -m repl.js 100 | + #-- will use the 'x86_64' version of 'qjsc' when architecture is not 'x86_64' 101 | + $(QJSC_X86_64) -c -o $@ -m repl.js 102 | 103 | qjscalc.c: $(QJSC) qjscalc.js 104 | - $(QJSC) -fbignum -c -o $@ qjscalc.js 105 | + #-- will use the 'x86_64' version of 'qjsc' when architecture is not 'x86_64' 106 | + $(QJSC_X86_64) -fbignum -c -o $@ qjscalc.js 107 | 108 | ifneq ($(wildcard unicode/UnicodeData.txt),) 109 | $(OBJDIR)/libunicode.o $(OBJDIR)/libunicode.m32.o $(OBJDIR)/libunicode.m32s.o \ 110 | @@ -297,9 +318,12 @@ clean: 111 | rm -rf $(OBJDIR)/ *.dSYM/ qjs-debug 112 | rm -rf run-test262-debug run-test262-32 113 | 114 | -install: all 115 | +#-- only install 116 | +#install: all 117 | +install: 118 | mkdir -p "$(DESTDIR)$(prefix)/bin" 119 | - $(STRIP) qjs qjsc 120 | + #-- disable stripping (because of cross-compiling) 121 | + #$(STRIP) qjs qjsc 122 | install -m755 qjs qjsc "$(DESTDIR)$(prefix)/bin" 123 | ln -sf qjs "$(DESTDIR)$(prefix)/bin/qjscalc" 124 | mkdir -p "$(DESTDIR)$(prefix)/lib/quickjs" 125 | @@ -323,7 +347,8 @@ HELLO_OPTS+=-fno-bigint 126 | endif 127 | 128 | hello.c: $(QJSC) $(HELLO_SRCS) 129 | - $(QJSC) -e $(HELLO_OPTS) -o $@ $(HELLO_SRCS) 130 | + #-- will use the 'x86_64' version of 'qjsc' when architecture is not 'x86_64' 131 | + $(QJSC_X86_64) -e $(HELLO_OPTS) -o $@ $(HELLO_SRCS) 132 | 133 | ifdef CONFIG_M32 134 | examples/hello: $(OBJDIR)/hello.m32s.o $(patsubst %.o, %.m32s.o, $(QJS_LIB_OBJS)) 135 | -------------------------------------------------------------------------------- /builder/custom/qjs/patches/2021-03-27/qjs.patch: -------------------------------------------------------------------------------- 1 | diff --git a/qjs.c b/qjs.c 2 | index d56b843..d6b32b6 100644 3 | --- a/qjs.c 4 | +++ b/qjs.c 5 | @@ -41,6 +41,8 @@ 6 | #include "cutils.h" 7 | #include "quickjs-libc.h" 8 | 9 | +#include "path.h" 10 | + 11 | extern const uint8_t qjsc_repl[]; 12 | extern const uint32_t qjsc_repl_size; 13 | #ifdef CONFIG_BIGNUM 14 | @@ -337,7 +339,9 @@ int main(int argc, char **argv) 15 | load_jscalc = !strcmp(exename, "qjscalc"); 16 | } 17 | #endif 18 | - 19 | + 20 | + set_exe_dir_from_exe_name(argv[0]); 21 | + 22 | /* cannot use getopt because we want to pass the command line to 23 | the script */ 24 | optind = 1; 25 | -------------------------------------------------------------------------------- /builder/custom/qjs/patches/2021-03-27/qjsc.patch: -------------------------------------------------------------------------------- 1 | diff --git a/qjsc.c b/qjsc.c 2 | index b9f1e4c..1150c1e 100644 3 | --- a/qjsc.c 4 | +++ b/qjsc.c 5 | @@ -36,6 +36,8 @@ 6 | #include "cutils.h" 7 | #include "quickjs-libc.h" 8 | 9 | +#include "path.h" 10 | + 11 | typedef struct { 12 | char *name; 13 | char *short_name; 14 | @@ -255,12 +257,31 @@ JSModuleDef *jsc_module_loader(JSContext *ctx, 15 | char cname[1024]; 16 | 17 | buf = js_load_file(ctx, &buf_len, module_name); 18 | +/* 19 | if (!buf) { 20 | JS_ThrowReferenceError(ctx, "could not load module filename '%s'", 21 | module_name); 22 | return NULL; 23 | } 24 | - 25 | +*/ 26 | + if (!buf) { 27 | + char path[4096]; 28 | + // check if a custom lib dir has been defined 29 | + char* lib_dir = getenv("QJS_LIB_DIR"); 30 | + if (NULL == lib_dir) { 31 | + get_path_with_exe_dir(path, sizeof(path), (char*)module_name); 32 | + } 33 | + else { 34 | + get_path_with_dir(path, sizeof(path), lib_dir, (char*)module_name); 35 | + } 36 | + buf = js_load_file(ctx, &buf_len, path); 37 | + if (!buf) { 38 | + JS_ThrowReferenceError(ctx, "could not load module filename '%s'", 39 | + module_name); 40 | + return NULL; 41 | + } 42 | + } 43 | + 44 | /* compile the module */ 45 | func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name, 46 | JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY); 47 | @@ -370,6 +391,13 @@ void help(void) 48 | printf("]\n" 49 | " disable selected language features (smaller code size)\n"); 50 | } 51 | +#else 52 | + //-- define '-fbignum' if 'CONFIG_BIGNUM' is defined 53 | + #ifdef CONFIG_BIGNUM 54 | + { 55 | + printf("-fbignum enable bignum extensions\n"); 56 | + } 57 | + #endif 58 | #endif 59 | exit(1); 60 | } 61 | @@ -401,6 +429,8 @@ static int output_executable(const char *out_filename, const char *cfilename, 62 | const char **arg, *bn_suffix, *lto_suffix; 63 | char libjsname[1024]; 64 | char exe_dir[1024], inc_dir[1024], lib_dir[1024], buf[1024], *p; 65 | + //-- used to store relative path to musl-gcc 66 | + char musl_gcc[4096]; 67 | int ret; 68 | 69 | /* get the directory of the executable */ 70 | @@ -427,8 +457,15 @@ static int output_executable(const char *out_filename, const char *cfilename, 71 | bn_suffix = ""; 72 | 73 | arg = argv; 74 | - *arg++ = CONFIG_CC; 75 | + //-- use included musl-gcc wrapper instead of default compiler 76 | + //*arg++ = CONFIG_CC; 77 | + snprintf(musl_gcc, sizeof(musl_gcc), "%s/musl-%s/bin/musl-gcc", exe_dir, MUSL_ARCH); 78 | + *arg++ = musl_gcc; 79 | *arg++ = "-O2"; 80 | + //-- force static compilation 81 | + *arg++ = "-static"; 82 | + //-- strip 83 | + *arg++ = "-s"; 84 | #ifdef CONFIG_LTO 85 | if (use_lto) { 86 | *arg++ = "-flto"; 87 | @@ -452,6 +489,8 @@ static int output_executable(const char *out_filename, const char *cfilename, 88 | *arg++ = "-lm"; 89 | *arg++ = "-ldl"; 90 | *arg++ = "-lpthread"; 91 | + //-- link to libatomic (armv7l) 92 | + *arg++ = "-latomic"; 93 | *arg = NULL; 94 | 95 | if (verbose) { 96 | @@ -462,6 +501,24 @@ static int output_executable(const char *out_filename, const char *cfilename, 97 | 98 | ret = exec_cmd((char **)argv); 99 | unlink(cfilename); 100 | + 101 | + //-- compress executable using upx 102 | + if (0 == ret) { 103 | + p = getenv("QJS_UPX"); 104 | + if (NULL != p && 0 == strcmp(p, "1")) { 105 | + arg = argv; 106 | + *arg++ = "upx"; 107 | + *arg++ = out_filename; 108 | + *arg = NULL; 109 | + if (verbose) { 110 | + for(arg = argv; *arg != NULL; arg++) 111 | + printf("%s ", *arg); 112 | + printf("\n"); 113 | + } 114 | + exec_cmd((char **)argv); 115 | + } 116 | + } 117 | + 118 | return ret; 119 | } 120 | #else 121 | @@ -513,6 +570,8 @@ int main(int argc, char **argv) 122 | namelist_add(&cmodule_list, "std", "std", 0); 123 | namelist_add(&cmodule_list, "os", "os", 0); 124 | 125 | + set_exe_dir_from_exe_name(argv[0]); 126 | + 127 | for(;;) { 128 | c = getopt(argc, argv, "ho:cN:f:mxevM:p:S:D:"); 129 | if (c == -1) 130 | -------------------------------------------------------------------------------- /builder/custom/qjs/patches/2021-03-27/quickjs-libc.patch: -------------------------------------------------------------------------------- 1 | diff --git a/quickjs-libc.c b/quickjs-libc.c 2 | index e180dd0..3fcfa79 100644 3 | --- a/quickjs-libc.c 4 | +++ b/quickjs-libc.c 5 | @@ -71,6 +71,13 @@ typedef sig_t sighandler_t; 6 | #include "list.h" 7 | #include "quickjs-libc.h" 8 | 9 | +#include "path.h" 10 | + 11 | +#if !defined(_WIN32) && !defined(__APPLE__) 12 | +// flock 13 | +#include 14 | +#endif /* !_WIN32 && !_APPLE_ 15 | + 16 | /* TODO: 17 | - add socket calls 18 | */ 19 | @@ -577,11 +584,30 @@ JSModuleDef *js_module_loader(JSContext *ctx, 20 | JSValue func_val; 21 | 22 | buf = js_load_file(ctx, &buf_len, module_name); 23 | +/* 24 | if (!buf) { 25 | JS_ThrowReferenceError(ctx, "could not load module filename '%s'", 26 | module_name); 27 | return NULL; 28 | } 29 | +*/ 30 | + if (!buf) { 31 | + char path[4096]; 32 | + // check if a custom lib dir has been defined 33 | + char* lib_dir = getenv("QJS_LIB_DIR"); 34 | + if (NULL == lib_dir) { 35 | + get_path_with_exe_dir(path, sizeof(path), (char*)module_name); 36 | + } 37 | + else { 38 | + get_path_with_dir(path, sizeof(path), lib_dir, (char*)module_name); 39 | + } 40 | + buf = js_load_file(ctx, &buf_len, path); 41 | + if (!buf) { 42 | + JS_ThrowReferenceError(ctx, "could not load module filename '%s'", 43 | + module_name); 44 | + return NULL; 45 | + } 46 | + } 47 | 48 | /* compile the module */ 49 | func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name, 50 | @@ -1477,6 +1503,13 @@ static const JSCFunctionListEntry js_std_error_props[] = { 51 | DEF(EPERM), 52 | DEF(EPIPE), 53 | DEF(EBADF), 54 | +#if !defined(_WIN32) && !defined(_APPLE_) 55 | + // flock 56 | + DEF(EINTR), 57 | + DEF(ENOLCK), 58 | + DEF(EWOULDBLOCK) 59 | +#endif /* !_WIN32 && !_APPLE_ */ 60 | + 61 | #undef DEF 62 | }; 63 | 64 | @@ -3030,6 +3063,13 @@ static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val, 65 | goto done; 66 | } 67 | 68 | +/* getpid() -> pid */ 69 | +static JSValue js_os_getpid(JSContext *ctx, JSValueConst this_val, 70 | + int argc, JSValueConst *argv) 71 | +{ 72 | + return JS_NewInt32(ctx, getpid()); 73 | +} 74 | + 75 | /* waitpid(pid, block) -> [pid, status] */ 76 | static JSValue js_os_waitpid(JSContext *ctx, JSValueConst this_val, 77 | int argc, JSValueConst *argv) 78 | @@ -3118,6 +3158,73 @@ static JSValue js_os_dup2(JSContext *ctx, JSValueConst this_val, 79 | return JS_NewInt32(ctx, ret); 80 | } 81 | 82 | +#if !defined(_APPLE_) 83 | + 84 | +/* flock(fd, operation) */ 85 | +static JSValue js_os_flock(JSContext *ctx, JSValueConst this_val, 86 | + int argc, JSValueConst *argv) 87 | +{ 88 | + int fd, operation, ret; 89 | + if (JS_ToInt32(ctx, &fd, argv[0])) 90 | + return JS_EXCEPTION; 91 | + if (JS_ToInt32(ctx, &operation, argv[1])) 92 | + return JS_EXCEPTION; 93 | + ret = js_get_errno(flock(fd, operation)); 94 | + return JS_NewInt32(ctx, ret); 95 | +} 96 | + 97 | +/* mkstemp(template, outputObj) */ 98 | +static JSValue js_os_mkstemp(JSContext *ctx, JSValueConst this_val, 99 | + int argc, JSValueConst *argv) 100 | +{ 101 | + char buffer[PATH_MAX]; 102 | + const char *template; 103 | + int ret; 104 | + 105 | + template = JS_ToCString(ctx, argv[0]); 106 | + if (!template) 107 | + return JS_EXCEPTION; 108 | + strncpy(buffer, template, sizeof(buffer)); 109 | + JS_FreeCString(ctx, template); 110 | + ret = js_get_errno(mkstemp(buffer)); 111 | + // check if we can pass the final filename back 112 | + if (argc >= 2 && ret > 0) { 113 | + if (!JS_IsUndefined(argv[1])) { 114 | + JS_SetPropertyStr(ctx, argv[1], "filename", JS_NewString(ctx, buffer)); 115 | + } 116 | + } 117 | + return JS_NewInt32(ctx, ret); 118 | +} 119 | + 120 | +/* mkdtemp(template, errorObj) */ 121 | +static JSValue js_os_mkdtemp(JSContext *ctx, JSValueConst this_val, 122 | + int argc, JSValueConst *argv) 123 | +{ 124 | + char buffer[PATH_MAX]; 125 | + const char *template; 126 | + const char *ptr; 127 | + int err = 0; 128 | + 129 | + template = JS_ToCString(ctx, argv[0]); 130 | + if (!template) 131 | + return JS_EXCEPTION; 132 | + strncpy(buffer, template, sizeof(buffer)); 133 | + JS_FreeCString(ctx, template); 134 | + ptr = mkdtemp(buffer); 135 | + if (NULL == ptr) { 136 | + err = errno; 137 | + } 138 | + if (argc >= 2) { 139 | + js_set_error_object(ctx, argv[1], err); 140 | + } 141 | + if (NULL == ptr) { 142 | + return JS_NULL; 143 | + } 144 | + return JS_NewString(ctx, ptr); 145 | +} 146 | + 147 | +#endif /* !_APPLE_ */ 148 | + 149 | #endif /* !_WIN32 */ 150 | 151 | #ifdef USE_WORKER 152 | @@ -3650,6 +3757,7 @@ static const JSCFunctionListEntry js_os_funcs[] = { 153 | JS_CFUNC_DEF("symlink", 2, js_os_symlink ), 154 | JS_CFUNC_DEF("readlink", 1, js_os_readlink ), 155 | JS_CFUNC_DEF("exec", 1, js_os_exec ), 156 | + JS_CFUNC_DEF("getpid", 0, js_os_getpid ), 157 | JS_CFUNC_DEF("waitpid", 2, js_os_waitpid ), 158 | OS_FLAG(WNOHANG), 159 | JS_CFUNC_DEF("pipe", 0, js_os_pipe ), 160 | @@ -3657,6 +3765,16 @@ static const JSCFunctionListEntry js_os_funcs[] = { 161 | JS_CFUNC_DEF("dup", 1, js_os_dup ), 162 | JS_CFUNC_DEF("dup2", 2, js_os_dup2 ), 163 | #endif 164 | +#if !defined(_WIN32) && !defined(_APPLE_) 165 | + // flock 166 | + JS_CFUNC_DEF("flock", 2, js_os_flock ), 167 | + OS_FLAG(LOCK_EX), 168 | + OS_FLAG(LOCK_NB), 169 | + // mkstemp 170 | + JS_CFUNC_DEF("mkstemp", 1, js_os_mkstemp ), 171 | + // mkdtemp 172 | + JS_CFUNC_DEF("mkdtemp", 1, js_os_mkdtemp ), 173 | +#endif 174 | }; 175 | 176 | static int js_os_init(JSContext *ctx, JSModuleDef *m) 177 | -------------------------------------------------------------------------------- /builder/custom/qjs/patches/2023-12-09/Makefile.patch: -------------------------------------------------------------------------------- 1 | diff --git a/Makefile b/Makefile 2 | index 39bd3ad..3975a93 100644 3 | --- a/Makefile 4 | +++ b/Makefile 5 | @@ -28,7 +28,8 @@ endif 6 | # Windows cross compilation from Linux 7 | #CONFIG_WIN32=y 8 | # use link time optimization (smaller and faster executables but slower build) 9 | -CONFIG_LTO=y 10 | +#-- disable LTO 11 | +#CONFIG_LTO=y 12 | # consider warnings as errors (for development) 13 | #CONFIG_WERROR=y 14 | # force 32 bit build for some utilities 15 | @@ -41,7 +42,9 @@ CONFIG_DEFAULT_AR=y 16 | endif 17 | 18 | # installation directory 19 | -prefix=/usr/local 20 | +#-- change prefix to / 21 | +#prefix=/usr/local 22 | +prefix=/ 23 | 24 | # use the gprof profiler 25 | #CONFIG_PROFILE=y 26 | @@ -86,7 +89,9 @@ ifdef CONFIG_CLANG 27 | endif 28 | else 29 | HOST_CC=gcc 30 | - CC=$(CROSS_PREFIX)gcc 31 | + #-- use musl-gcc instead of gcc (symlink must exist) 32 | + #CC=$(CROSS_PREFIX)gcc 33 | + CC=$(CURDIR)/musl-$(musl_arch)/bin/musl-gcc 34 | CFLAGS=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d 35 | CFLAGS += -Wno-array-bounds -Wno-format-truncation 36 | ifdef CONFIG_LTO 37 | @@ -100,6 +105,8 @@ ifdef CONFIG_WERROR 38 | CFLAGS+=-Werror 39 | endif 40 | DEFINES:=-D_GNU_SOURCE -DCONFIG_VERSION=\"$(shell cat VERSION)\" 41 | +#-- define target architecture 42 | +DEFINES+=-DMUSL_ARCH=\"$(musl_arch)\" 43 | ifdef CONFIG_BIGNUM 44 | DEFINES+=-DCONFIG_BIGNUM 45 | endif 46 | @@ -113,6 +120,10 @@ CFLAGS_SMALL=$(CFLAGS) -Os 47 | CFLAGS_OPT=$(CFLAGS) -O2 48 | CFLAGS_NOLTO:=$(CFLAGS_OPT) 49 | LDFLAGS=-g 50 | +#-- force static compilation 51 | +LDFLAGS+=-static 52 | +#-- disable PIE 53 | +CFLAGS+=-no-pie 54 | ifdef CONFIG_LTO 55 | CFLAGS_SMALL+=-flto 56 | CFLAGS_OPT+=-flto 57 | @@ -152,12 +163,17 @@ ifdef CONFIG_LTO 58 | PROGS+=libquickjs.lto.a 59 | endif 60 | 61 | +#--when architecture is not 'x86_64', we need to use the 'x86_64' version of the 'qjsc' binary to generate c files 62 | +QJSC_X86_64=$(qjsc_binary) 63 | + 64 | # examples 65 | ifeq ($(CROSS_PREFIX),) 66 | ifdef CONFIG_ASAN 67 | PROGS+= 68 | else 69 | -PROGS+=examples/hello examples/hello_module examples/test_fib 70 | +#-- disable 'hello_module' & 'test_fib' examples because of cross-compilation 71 | +#PROGS+=examples/hello examples/hello_module examples/test_fib 72 | +PROGS+=examples/hello 73 | ifndef CONFIG_DARWIN 74 | PROGS+=examples/fib.so examples/point.so 75 | endif 76 | @@ -166,7 +182,7 @@ endif 77 | 78 | all: $(OBJDIR) $(OBJDIR)/quickjs.check.o $(OBJDIR)/qjs.check.o $(PROGS) 79 | 80 | -QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o $(OBJDIR)/libbf.o 81 | +QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o $(OBJDIR)/libbf.o $(OBJDIR)/path.o 82 | 83 | QJS_OBJS=$(OBJDIR)/qjs.o $(OBJDIR)/repl.o $(QJS_LIB_OBJS) 84 | ifdef CONFIG_BIGNUM 85 | @@ -180,6 +196,9 @@ LIBS+=-ldl -lpthread 86 | endif 87 | LIBS+=$(EXTRA_LIBS) 88 | 89 | +#-- static linking to libatomic (necessary for armv7l) 90 | +LIBS+=-L $(CURDIR)/musl-$(musl_arch)/lib -latomic 91 | + 92 | $(OBJDIR): 93 | mkdir -p $(OBJDIR) $(OBJDIR)/examples $(OBJDIR)/tests 94 | 95 | @@ -234,10 +253,12 @@ libquickjs.a: $(patsubst %.o, %.nolto.o, $(QJS_LIB_OBJS)) 96 | endif # CONFIG_LTO 97 | 98 | repl.c: $(QJSC) repl.js 99 | - $(QJSC) -c -o $@ -m repl.js 100 | + #-- will use the 'x86_64' version of 'qjsc' when architecture is not 'x86_64' 101 | + $(QJSC_X86_64) -c -o $@ -m repl.js 102 | 103 | qjscalc.c: $(QJSC) qjscalc.js 104 | - $(QJSC) -fbignum -c -o $@ qjscalc.js 105 | + #-- will use the 'x86_64' version of 'qjsc' when architecture is not 'x86_64' 106 | + $(QJSC_X86_64) -fbignum -c -o $@ qjscalc.js 107 | 108 | ifneq ($(wildcard unicode/UnicodeData.txt),) 109 | $(OBJDIR)/libunicode.o $(OBJDIR)/libunicode.m32.o $(OBJDIR)/libunicode.m32s.o \ 110 | @@ -296,9 +317,12 @@ clean: 111 | rm -rf $(OBJDIR)/ *.dSYM/ qjs-debug 112 | rm -rf run-test262-debug run-test262-32 113 | 114 | -install: all 115 | +#-- only install 116 | +#install: all 117 | +install: 118 | mkdir -p "$(DESTDIR)$(prefix)/bin" 119 | - $(STRIP) qjs qjsc 120 | + #-- disable stripping (because of cross-compiling) 121 | + #$(STRIP) qjs qjsc 122 | install -m755 qjs qjsc "$(DESTDIR)$(prefix)/bin" 123 | ln -sf qjs "$(DESTDIR)$(prefix)/bin/qjscalc" 124 | mkdir -p "$(DESTDIR)$(prefix)/lib/quickjs" 125 | @@ -319,7 +343,8 @@ HELLO_OPTS=-fno-string-normalize -fno-map -fno-promise -fno-typedarray \ 126 | -fno-date -fno-module-loader -fno-bigint 127 | 128 | hello.c: $(QJSC) $(HELLO_SRCS) 129 | - $(QJSC) -e $(HELLO_OPTS) -o $@ $(HELLO_SRCS) 130 | + #-- will use the 'x86_64' version of 'qjsc' when architecture is not 'x86_64' 131 | + $(QJSC_X86_64) -e $(HELLO_OPTS) -o $@ $(HELLO_SRCS) 132 | 133 | ifdef CONFIG_M32 134 | examples/hello: $(OBJDIR)/hello.m32s.o $(patsubst %.o, %.m32s.o, $(QJS_LIB_OBJS)) 135 | -------------------------------------------------------------------------------- /builder/custom/qjs/patches/2023-12-09/qjs.patch: -------------------------------------------------------------------------------- 1 | diff --git a/qjs.c b/qjs.c 2 | index c2d63e9..8084d8f 100644 3 | --- a/qjs.c 4 | +++ b/qjs.c 5 | @@ -41,6 +41,8 @@ 6 | #include "cutils.h" 7 | #include "quickjs-libc.h" 8 | 9 | +#include "path.h" 10 | + 11 | extern const uint8_t qjsc_repl[]; 12 | extern const uint32_t qjsc_repl_size; 13 | #ifdef CONFIG_BIGNUM 14 | @@ -337,7 +339,9 @@ int main(int argc, char **argv) 15 | load_jscalc = !strcmp(exename, "qjscalc"); 16 | } 17 | #endif 18 | - 19 | + 20 | + set_exe_dir_from_exe_name(argv[0]); 21 | + 22 | /* cannot use getopt because we want to pass the command line to 23 | the script */ 24 | optind = 1; 25 | -------------------------------------------------------------------------------- /builder/custom/qjs/patches/2023-12-09/qjsc.patch: -------------------------------------------------------------------------------- 1 | diff --git a/qjsc.c b/qjsc.c 2 | index d317826..26261b9 100644 3 | --- a/qjsc.c 4 | +++ b/qjsc.c 5 | @@ -36,6 +36,8 @@ 6 | #include "cutils.h" 7 | #include "quickjs-libc.h" 8 | 9 | +#include "path.h" 10 | + 11 | typedef struct { 12 | char *name; 13 | char *short_name; 14 | @@ -253,12 +255,31 @@ JSModuleDef *jsc_module_loader(JSContext *ctx, 15 | char cname[1024]; 16 | 17 | buf = js_load_file(ctx, &buf_len, module_name); 18 | +/* 19 | if (!buf) { 20 | JS_ThrowReferenceError(ctx, "could not load module filename '%s'", 21 | module_name); 22 | return NULL; 23 | } 24 | - 25 | +*/ 26 | + if (!buf) { 27 | + char path[4096]; 28 | + // check if a custom lib dir has been defined 29 | + char* lib_dir = getenv("QJS_LIB_DIR"); 30 | + if (NULL == lib_dir) { 31 | + get_path_with_exe_dir(path, sizeof(path), (char*)module_name); 32 | + } 33 | + else { 34 | + get_path_with_dir(path, sizeof(path), lib_dir, (char*)module_name); 35 | + } 36 | + buf = js_load_file(ctx, &buf_len, path); 37 | + if (!buf) { 38 | + JS_ThrowReferenceError(ctx, "could not load module filename '%s'", 39 | + module_name); 40 | + return NULL; 41 | + } 42 | + } 43 | + 44 | /* compile the module */ 45 | func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name, 46 | JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY); 47 | @@ -368,6 +389,13 @@ void help(void) 48 | printf("]\n" 49 | " disable selected language features (smaller code size)\n"); 50 | } 51 | +#else 52 | + //-- define '-fbignum' if 'CONFIG_BIGNUM' is defined 53 | + #ifdef CONFIG_BIGNUM 54 | + { 55 | + printf("-fbignum enable bignum extensions\n"); 56 | + } 57 | + #endif 58 | #endif 59 | exit(1); 60 | } 61 | @@ -399,6 +427,8 @@ static int output_executable(const char *out_filename, const char *cfilename, 62 | const char **arg, *bn_suffix, *lto_suffix; 63 | char libjsname[1024]; 64 | char exe_dir[1024], inc_dir[1024], lib_dir[1024], buf[1024], *p; 65 | + //-- used to store relative path to musl-gcc 66 | + char musl_gcc[4096]; 67 | int ret; 68 | 69 | /* get the directory of the executable */ 70 | @@ -425,8 +455,15 @@ static int output_executable(const char *out_filename, const char *cfilename, 71 | bn_suffix = ""; 72 | 73 | arg = argv; 74 | - *arg++ = CONFIG_CC; 75 | + //-- use included musl-gcc wrapper instead of default compiler 76 | + //*arg++ = CONFIG_CC; 77 | + snprintf(musl_gcc, sizeof(musl_gcc), "%s/musl-%s/bin/musl-gcc", exe_dir, MUSL_ARCH); 78 | + *arg++ = musl_gcc; 79 | *arg++ = "-O2"; 80 | + //-- force static compilation 81 | + *arg++ = "-static"; 82 | + //-- strip 83 | + *arg++ = "-s"; 84 | #ifdef CONFIG_LTO 85 | if (use_lto) { 86 | *arg++ = "-flto"; 87 | @@ -450,6 +487,8 @@ static int output_executable(const char *out_filename, const char *cfilename, 88 | *arg++ = "-lm"; 89 | *arg++ = "-ldl"; 90 | *arg++ = "-lpthread"; 91 | + //-- link to libatomic (armv7l) 92 | + *arg++ = "-latomic"; 93 | *arg = NULL; 94 | 95 | if (verbose) { 96 | @@ -460,6 +499,24 @@ static int output_executable(const char *out_filename, const char *cfilename, 97 | 98 | ret = exec_cmd((char **)argv); 99 | unlink(cfilename); 100 | + 101 | + //-- compress executable using upx 102 | + if (0 == ret) { 103 | + p = getenv("QJS_UPX"); 104 | + if (NULL != p && 0 == strcmp(p, "1")) { 105 | + arg = argv; 106 | + *arg++ = "upx"; 107 | + *arg++ = out_filename; 108 | + *arg = NULL; 109 | + if (verbose) { 110 | + for(arg = argv; *arg != NULL; arg++) 111 | + printf("%s ", *arg); 112 | + printf("\n"); 113 | + } 114 | + exec_cmd((char **)argv); 115 | + } 116 | + } 117 | + 118 | return ret; 119 | } 120 | #else 121 | @@ -511,6 +568,8 @@ int main(int argc, char **argv) 122 | namelist_add(&cmodule_list, "std", "std", 0); 123 | namelist_add(&cmodule_list, "os", "os", 0); 124 | 125 | + set_exe_dir_from_exe_name(argv[0]); 126 | + 127 | for(;;) { 128 | c = getopt(argc, argv, "ho:cN:f:mxevM:p:S:D:"); 129 | if (c == -1) 130 | -------------------------------------------------------------------------------- /builder/custom/qjs/patches/2023-12-09/quickjs-libc.patch: -------------------------------------------------------------------------------- 1 | diff --git a/quickjs-libc.c b/quickjs-libc.c 2 | index e180dd0..3fcfa79 100644 3 | --- a/quickjs-libc.c 4 | +++ b/quickjs-libc.c 5 | @@ -71,6 +71,13 @@ typedef sig_t sighandler_t; 6 | #include "list.h" 7 | #include "quickjs-libc.h" 8 | 9 | +#include "path.h" 10 | + 11 | +#if !defined(_WIN32) && !defined(__APPLE__) 12 | +// flock 13 | +#include 14 | +#endif /* !_WIN32 && !_APPLE_ 15 | + 16 | /* TODO: 17 | - add socket calls 18 | */ 19 | @@ -577,11 +584,30 @@ JSModuleDef *js_module_loader(JSContext *ctx, 20 | JSValue func_val; 21 | 22 | buf = js_load_file(ctx, &buf_len, module_name); 23 | +/* 24 | if (!buf) { 25 | JS_ThrowReferenceError(ctx, "could not load module filename '%s'", 26 | module_name); 27 | return NULL; 28 | } 29 | +*/ 30 | + if (!buf) { 31 | + char path[4096]; 32 | + // check if a custom lib dir has been defined 33 | + char* lib_dir = getenv("QJS_LIB_DIR"); 34 | + if (NULL == lib_dir) { 35 | + get_path_with_exe_dir(path, sizeof(path), (char*)module_name); 36 | + } 37 | + else { 38 | + get_path_with_dir(path, sizeof(path), lib_dir, (char*)module_name); 39 | + } 40 | + buf = js_load_file(ctx, &buf_len, path); 41 | + if (!buf) { 42 | + JS_ThrowReferenceError(ctx, "could not load module filename '%s'", 43 | + module_name); 44 | + return NULL; 45 | + } 46 | + } 47 | 48 | /* compile the module */ 49 | func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name, 50 | @@ -1477,6 +1503,13 @@ static const JSCFunctionListEntry js_std_error_props[] = { 51 | DEF(EPERM), 52 | DEF(EPIPE), 53 | DEF(EBADF), 54 | +#if !defined(_WIN32) && !defined(_APPLE_) 55 | + // flock 56 | + DEF(EINTR), 57 | + DEF(ENOLCK), 58 | + DEF(EWOULDBLOCK) 59 | +#endif /* !_WIN32 && !_APPLE_ */ 60 | + 61 | #undef DEF 62 | }; 63 | 64 | @@ -3030,6 +3063,13 @@ static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val, 65 | goto done; 66 | } 67 | 68 | +/* getpid() -> pid */ 69 | +static JSValue js_os_getpid(JSContext *ctx, JSValueConst this_val, 70 | + int argc, JSValueConst *argv) 71 | +{ 72 | + return JS_NewInt32(ctx, getpid()); 73 | +} 74 | + 75 | /* waitpid(pid, block) -> [pid, status] */ 76 | static JSValue js_os_waitpid(JSContext *ctx, JSValueConst this_val, 77 | int argc, JSValueConst *argv) 78 | @@ -3118,6 +3158,73 @@ static JSValue js_os_dup2(JSContext *ctx, JSValueConst this_val, 79 | return JS_NewInt32(ctx, ret); 80 | } 81 | 82 | +#if !defined(_APPLE_) 83 | + 84 | +/* flock(fd, operation) */ 85 | +static JSValue js_os_flock(JSContext *ctx, JSValueConst this_val, 86 | + int argc, JSValueConst *argv) 87 | +{ 88 | + int fd, operation, ret; 89 | + if (JS_ToInt32(ctx, &fd, argv[0])) 90 | + return JS_EXCEPTION; 91 | + if (JS_ToInt32(ctx, &operation, argv[1])) 92 | + return JS_EXCEPTION; 93 | + ret = js_get_errno(flock(fd, operation)); 94 | + return JS_NewInt32(ctx, ret); 95 | +} 96 | + 97 | +/* mkstemp(template, outputObj) */ 98 | +static JSValue js_os_mkstemp(JSContext *ctx, JSValueConst this_val, 99 | + int argc, JSValueConst *argv) 100 | +{ 101 | + char buffer[PATH_MAX]; 102 | + const char *template; 103 | + int ret; 104 | + 105 | + template = JS_ToCString(ctx, argv[0]); 106 | + if (!template) 107 | + return JS_EXCEPTION; 108 | + strncpy(buffer, template, sizeof(buffer)); 109 | + JS_FreeCString(ctx, template); 110 | + ret = js_get_errno(mkstemp(buffer)); 111 | + // check if we can pass the final filename back 112 | + if (argc >= 2 && ret > 0) { 113 | + if (!JS_IsUndefined(argv[1])) { 114 | + JS_SetPropertyStr(ctx, argv[1], "filename", JS_NewString(ctx, buffer)); 115 | + } 116 | + } 117 | + return JS_NewInt32(ctx, ret); 118 | +} 119 | + 120 | +/* mkdtemp(template, errorObj) */ 121 | +static JSValue js_os_mkdtemp(JSContext *ctx, JSValueConst this_val, 122 | + int argc, JSValueConst *argv) 123 | +{ 124 | + char buffer[PATH_MAX]; 125 | + const char *template; 126 | + const char *ptr; 127 | + int err = 0; 128 | + 129 | + template = JS_ToCString(ctx, argv[0]); 130 | + if (!template) 131 | + return JS_EXCEPTION; 132 | + strncpy(buffer, template, sizeof(buffer)); 133 | + JS_FreeCString(ctx, template); 134 | + ptr = mkdtemp(buffer); 135 | + if (NULL == ptr) { 136 | + err = errno; 137 | + } 138 | + if (argc >= 2) { 139 | + js_set_error_object(ctx, argv[1], err); 140 | + } 141 | + if (NULL == ptr) { 142 | + return JS_NULL; 143 | + } 144 | + return JS_NewString(ctx, ptr); 145 | +} 146 | + 147 | +#endif /* !_APPLE_ */ 148 | + 149 | #endif /* !_WIN32 */ 150 | 151 | #ifdef USE_WORKER 152 | @@ -3650,6 +3757,7 @@ static const JSCFunctionListEntry js_os_funcs[] = { 153 | JS_CFUNC_DEF("symlink", 2, js_os_symlink ), 154 | JS_CFUNC_DEF("readlink", 1, js_os_readlink ), 155 | JS_CFUNC_DEF("exec", 1, js_os_exec ), 156 | + JS_CFUNC_DEF("getpid", 0, js_os_getpid ), 157 | JS_CFUNC_DEF("waitpid", 2, js_os_waitpid ), 158 | OS_FLAG(WNOHANG), 159 | JS_CFUNC_DEF("pipe", 0, js_os_pipe ), 160 | @@ -3657,6 +3765,16 @@ static const JSCFunctionListEntry js_os_funcs[] = { 161 | JS_CFUNC_DEF("dup", 1, js_os_dup ), 162 | JS_CFUNC_DEF("dup2", 2, js_os_dup2 ), 163 | #endif 164 | +#if !defined(_WIN32) && !defined(_APPLE_) 165 | + // flock 166 | + JS_CFUNC_DEF("flock", 2, js_os_flock ), 167 | + OS_FLAG(LOCK_EX), 168 | + OS_FLAG(LOCK_NB), 169 | + // mkstemp 170 | + JS_CFUNC_DEF("mkstemp", 1, js_os_mkstemp ), 171 | + // mkdtemp 172 | + JS_CFUNC_DEF("mkdtemp", 1, js_os_mkdtemp ), 173 | +#endif 174 | }; 175 | 176 | static int js_os_init(JSContext *ctx, JSModuleDef *m) 177 | -------------------------------------------------------------------------------- /builder/custom/qjs/patches/2024-01-13/Makefile.patch: -------------------------------------------------------------------------------- 1 | diff --git a/Makefile b/Makefile 2 | index 57cdd7e..d037ebf 100644 3 | --- a/Makefile 4 | +++ b/Makefile 5 | @@ -28,7 +28,8 @@ endif 6 | # Windows cross compilation from Linux 7 | #CONFIG_WIN32=y 8 | # use link time optimization (smaller and faster executables but slower build) 9 | -CONFIG_LTO=y 10 | +#-- disable LTO 11 | +#CONFIG_LTO=y 12 | # consider warnings as errors (for development) 13 | #CONFIG_WERROR=y 14 | # force 32 bit build for some utilities 15 | @@ -37,7 +38,10 @@ CONFIG_LTO=y 16 | #CONFIG_COSMO=y 17 | 18 | # installation directory 19 | -PREFIX?=/usr/local 20 | +#PREFIX?=/usr/local 21 | +#-- change prefix to / 22 | +PREFIX?=/ 23 | + 24 | 25 | # use the gprof profiler 26 | #CONFIG_PROFILE=y 27 | @@ -97,7 +101,9 @@ else ifdef CONFIG_COSMO 28 | AR=cosmoar 29 | else 30 | HOST_CC=gcc 31 | - CC=$(CROSS_PREFIX)gcc 32 | + #-- use musl-gcc instead of gcc (symlink must exist) 33 | + #CC=$(CROSS_PREFIX)gcc 34 | + CC=$(CURDIR)/musl-$(musl_arch)/bin/musl-gcc 35 | CFLAGS+=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d 36 | CFLAGS += -Wno-array-bounds -Wno-format-truncation 37 | ifdef CONFIG_LTO 38 | @@ -112,6 +118,8 @@ ifdef CONFIG_WERROR 39 | CFLAGS+=-Werror 40 | endif 41 | DEFINES:=-D_GNU_SOURCE -DCONFIG_VERSION=\"$(shell cat VERSION)\" 42 | +#-- define target architecture 43 | +DEFINES+=-DMUSL_ARCH=\"$(musl_arch)\" 44 | ifdef CONFIG_BIGNUM 45 | DEFINES+=-DCONFIG_BIGNUM 46 | endif 47 | @@ -128,6 +136,10 @@ ifdef CONFIG_COSMO 48 | LDFLAGS+=-s # better to strip by default 49 | else 50 | LDFLAGS+=-g 51 | +#-- force static compilation 52 | +LDFLAGS+=-static 53 | +#-- disable PIE 54 | +CFLAGS+=-no-pie 55 | endif 56 | ifdef CONFIG_LTO 57 | CFLAGS_SMALL+=-flto 58 | @@ -174,20 +186,25 @@ ifdef CONFIG_LTO 59 | PROGS+=libquickjs.lto.a 60 | endif 61 | 62 | +#--when architecture is not 'x86_64', we need to use the 'x86_64' version of the 'qjsc' binary to generate c files 63 | +QJSC_X86_64=$(qjsc_binary) 64 | + 65 | # examples 66 | ifeq ($(CROSS_PREFIX),) 67 | PROGS+=examples/hello 68 | ifndef CONFIG_ASAN 69 | -PROGS+=examples/hello_module 70 | +#-- disable because of cross-compilation 71 | +#PROGS+=examples/hello_module 72 | endif 73 | ifdef CONFIG_SHARED_LIBS 74 | -PROGS+=examples/test_fib examples/fib.so examples/point.so 75 | +#-- disable because of cross-compilation 76 | +#PROGS+=examples/test_fib examples/fib.so examples/point.so 77 | endif 78 | endif 79 | 80 | all: $(OBJDIR) $(OBJDIR)/quickjs.check.o $(OBJDIR)/qjs.check.o $(PROGS) 81 | 82 | -QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o $(OBJDIR)/libbf.o 83 | +QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o $(OBJDIR)/libbf.o $(OBJDIR)/path.o 84 | 85 | QJS_OBJS=$(OBJDIR)/qjs.o $(OBJDIR)/repl.o $(QJS_LIB_OBJS) 86 | ifdef CONFIG_BIGNUM 87 | @@ -201,6 +218,9 @@ LIBS+=-ldl -lpthread 88 | endif 89 | LIBS+=$(EXTRA_LIBS) 90 | 91 | +#-- static linking to libatomic (necessary for armv7l) 92 | +LIBS+=-L $(CURDIR)/musl-$(musl_arch)/lib -latomic 93 | + 94 | $(OBJDIR): 95 | mkdir -p $(OBJDIR) $(OBJDIR)/examples $(OBJDIR)/tests 96 | 97 | @@ -255,10 +275,12 @@ libquickjs.a: $(patsubst %.o, %.nolto.o, $(QJS_LIB_OBJS)) 98 | endif # CONFIG_LTO 99 | 100 | repl.c: $(QJSC) repl.js 101 | - $(QJSC) -c -o $@ -m repl.js 102 | + #-- will use the 'x86_64' version of 'qjsc' when architecture is not 'x86_64' 103 | + $(QJSC_X86_64) -c -o $@ -m repl.js 104 | 105 | qjscalc.c: $(QJSC) qjscalc.js 106 | - $(QJSC) -fbignum -c -o $@ qjscalc.js 107 | + #-- will use the 'x86_64' version of 'qjsc' when architecture is not 'x86_64' 108 | + $(QJSC_X86_64) -fbignum -c -o $@ qjscalc.js 109 | 110 | ifneq ($(wildcard unicode/UnicodeData.txt),) 111 | $(OBJDIR)/libunicode.o $(OBJDIR)/libunicode.m32.o $(OBJDIR)/libunicode.m32s.o \ 112 | @@ -317,9 +339,12 @@ clean: 113 | rm -rf $(OBJDIR)/ *.dSYM/ qjs-debug 114 | rm -rf run-test262-debug run-test262-32 115 | 116 | -install: all 117 | +#-- only install 118 | +#install: all 119 | +install: 120 | mkdir -p "$(DESTDIR)$(PREFIX)/bin" 121 | - $(STRIP) qjs qjsc 122 | + #-- disable stripping (because of cross-compiling) 123 | + #$(STRIP) qjs qjsc 124 | install -m755 qjs qjsc "$(DESTDIR)$(PREFIX)/bin" 125 | ln -sf qjs "$(DESTDIR)$(PREFIX)/bin/qjscalc" 126 | mkdir -p "$(DESTDIR)$(PREFIX)/lib/quickjs" 127 | @@ -340,7 +365,8 @@ HELLO_OPTS=-fno-string-normalize -fno-map -fno-promise -fno-typedarray \ 128 | -fno-date -fno-module-loader -fno-bigint 129 | 130 | hello.c: $(QJSC) $(HELLO_SRCS) 131 | - $(QJSC) -e $(HELLO_OPTS) -o $@ $(HELLO_SRCS) 132 | + #-- will use the 'x86_64' version of 'qjsc' when architecture is not 'x86_64' 133 | + $(QJSC_X86_64) -e $(HELLO_OPTS) -o $@ $(HELLO_SRCS) 134 | 135 | ifdef CONFIG_M32 136 | examples/hello: $(OBJDIR)/hello.m32s.o $(patsubst %.o, %.m32s.o, $(QJS_LIB_OBJS)) 137 | -------------------------------------------------------------------------------- /builder/custom/qjs/patches/2024-01-13/qjs.patch: -------------------------------------------------------------------------------- 1 | diff --git a/qjs.c b/qjs.c 2 | index 77b5cfb..ad684e9 100644 3 | --- a/qjs.c 4 | +++ b/qjs.c 5 | @@ -41,6 +41,8 @@ 6 | #include "cutils.h" 7 | #include "quickjs-libc.h" 8 | 9 | +#include "path.h" 10 | + 11 | extern const uint8_t qjsc_repl[]; 12 | extern const uint32_t qjsc_repl_size; 13 | #ifdef CONFIG_BIGNUM 14 | @@ -326,7 +328,9 @@ int main(int argc, char **argv) 15 | load_jscalc = !strcmp(exename, "qjscalc"); 16 | } 17 | #endif 18 | - 19 | + 20 | + set_exe_dir_from_exe_name(argv[0]); 21 | + 22 | /* cannot use getopt because we want to pass the command line to 23 | the script */ 24 | optind = 1; 25 | -------------------------------------------------------------------------------- /builder/custom/qjs/patches/2024-01-13/qjsc.patch: -------------------------------------------------------------------------------- 1 | diff --git a/qjsc.c b/qjsc.c 2 | index f8e60b3..0505445 100644 3 | --- a/qjsc.c 4 | +++ b/qjsc.c 5 | @@ -36,6 +36,8 @@ 6 | #include "cutils.h" 7 | #include "quickjs-libc.h" 8 | 9 | +#include "path.h" 10 | + 11 | typedef struct { 12 | char *name; 13 | char *short_name; 14 | @@ -253,12 +255,31 @@ JSModuleDef *jsc_module_loader(JSContext *ctx, 15 | char cname[1024]; 16 | 17 | buf = js_load_file(ctx, &buf_len, module_name); 18 | +/* 19 | if (!buf) { 20 | JS_ThrowReferenceError(ctx, "could not load module filename '%s'", 21 | module_name); 22 | return NULL; 23 | } 24 | - 25 | +*/ 26 | + if (!buf) { 27 | + char path[4096]; 28 | + // check if a custom lib dir has been defined 29 | + char* lib_dir = getenv("QJS_LIB_DIR"); 30 | + if (NULL == lib_dir) { 31 | + get_path_with_exe_dir(path, sizeof(path), (char*)module_name); 32 | + } 33 | + else { 34 | + get_path_with_dir(path, sizeof(path), lib_dir, (char*)module_name); 35 | + } 36 | + buf = js_load_file(ctx, &buf_len, path); 37 | + if (!buf) { 38 | + JS_ThrowReferenceError(ctx, "could not load module filename '%s'", 39 | + module_name); 40 | + return NULL; 41 | + } 42 | + } 43 | + 44 | /* compile the module */ 45 | func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name, 46 | JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY); 47 | @@ -369,6 +390,13 @@ void help(void) 48 | printf("]\n" 49 | " disable selected language features (smaller code size)\n"); 50 | } 51 | +#else 52 | + //-- define '-fbignum' if 'CONFIG_BIGNUM' is defined 53 | + #ifdef CONFIG_BIGNUM 54 | + { 55 | + printf("-fbignum enable bignum extensions\n"); 56 | + } 57 | + #endif 58 | #endif 59 | exit(1); 60 | } 61 | @@ -400,6 +428,8 @@ static int output_executable(const char *out_filename, const char *cfilename, 62 | const char **arg, *bn_suffix, *lto_suffix; 63 | char libjsname[1024]; 64 | char exe_dir[1024], inc_dir[1024], lib_dir[1024], buf[1024], *p; 65 | + //-- used to store relative path to musl-gcc 66 | + char musl_gcc[4096]; 67 | int ret; 68 | 69 | /* get the directory of the executable */ 70 | @@ -426,8 +456,15 @@ static int output_executable(const char *out_filename, const char *cfilename, 71 | bn_suffix = ""; 72 | 73 | arg = argv; 74 | - *arg++ = CONFIG_CC; 75 | + //-- use included musl-gcc wrapper instead of default compiler 76 | + //*arg++ = CONFIG_CC; 77 | + snprintf(musl_gcc, sizeof(musl_gcc), "%s/musl-%s/bin/musl-gcc", exe_dir, MUSL_ARCH); 78 | + *arg++ = musl_gcc; 79 | *arg++ = "-O2"; 80 | + //-- force static compilation 81 | + *arg++ = "-static"; 82 | + //-- strip 83 | + *arg++ = "-s"; 84 | #ifdef CONFIG_LTO 85 | if (use_lto) { 86 | *arg++ = "-flto"; 87 | @@ -451,6 +488,8 @@ static int output_executable(const char *out_filename, const char *cfilename, 88 | *arg++ = "-lm"; 89 | *arg++ = "-ldl"; 90 | *arg++ = "-lpthread"; 91 | + //-- link to libatomic (armv7l) 92 | + *arg++ = "-latomic"; 93 | *arg = NULL; 94 | 95 | if (verbose) { 96 | @@ -461,6 +500,24 @@ static int output_executable(const char *out_filename, const char *cfilename, 97 | 98 | ret = exec_cmd((char **)argv); 99 | unlink(cfilename); 100 | + 101 | + //-- compress executable using upx 102 | + if (0 == ret) { 103 | + p = getenv("QJS_UPX"); 104 | + if (NULL != p && 0 == strcmp(p, "1")) { 105 | + arg = argv; 106 | + *arg++ = "upx"; 107 | + *arg++ = out_filename; 108 | + *arg = NULL; 109 | + if (verbose) { 110 | + for(arg = argv; *arg != NULL; arg++) 111 | + printf("%s ", *arg); 112 | + printf("\n"); 113 | + } 114 | + exec_cmd((char **)argv); 115 | + } 116 | + } 117 | + 118 | return ret; 119 | } 120 | #else 121 | @@ -512,6 +569,8 @@ int main(int argc, char **argv) 122 | namelist_add(&cmodule_list, "std", "std", 0); 123 | namelist_add(&cmodule_list, "os", "os", 0); 124 | 125 | + set_exe_dir_from_exe_name(argv[0]); 126 | + 127 | for(;;) { 128 | c = getopt(argc, argv, "ho:cN:f:mxevM:p:S:D:"); 129 | if (c == -1) 130 | -------------------------------------------------------------------------------- /builder/custom/qjs/patches/2024-01-13/quickjs-libc.patch: -------------------------------------------------------------------------------- 1 | diff --git a/quickjs-libc.c b/quickjs-libc.c 2 | index d4f4d67..26d7f7f 100644 3 | --- a/quickjs-libc.c 4 | +++ b/quickjs-libc.c 5 | @@ -71,6 +71,13 @@ typedef sig_t sighandler_t; 6 | #include "list.h" 7 | #include "quickjs-libc.h" 8 | 9 | +#include "path.h" 10 | + 11 | +#if !defined(_WIN32) && !defined(__APPLE__) 12 | +// flock 13 | +#include 14 | +#endif /* !_WIN32 && !_APPLE_ 15 | + 16 | /* TODO: 17 | - add socket calls 18 | */ 19 | @@ -577,11 +584,30 @@ JSModuleDef *js_module_loader(JSContext *ctx, 20 | JSValue func_val; 21 | 22 | buf = js_load_file(ctx, &buf_len, module_name); 23 | +/* 24 | if (!buf) { 25 | JS_ThrowReferenceError(ctx, "could not load module filename '%s'", 26 | module_name); 27 | return NULL; 28 | } 29 | +*/ 30 | + if (!buf) { 31 | + char path[4096]; 32 | + // check if a custom lib dir has been defined 33 | + char* lib_dir = getenv("QJS_LIB_DIR"); 34 | + if (NULL == lib_dir) { 35 | + get_path_with_exe_dir(path, sizeof(path), (char*)module_name); 36 | + } 37 | + else { 38 | + get_path_with_dir(path, sizeof(path), lib_dir, (char*)module_name); 39 | + } 40 | + buf = js_load_file(ctx, &buf_len, path); 41 | + if (!buf) { 42 | + JS_ThrowReferenceError(ctx, "could not load module filename '%s'", 43 | + module_name); 44 | + return NULL; 45 | + } 46 | + } 47 | 48 | /* compile the module */ 49 | func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name, 50 | @@ -1483,6 +1509,13 @@ static const JSCFunctionListEntry js_std_error_props[] = { 51 | DEF(EPERM), 52 | DEF(EPIPE), 53 | DEF(EBADF), 54 | +#if !defined(_WIN32) && !defined(_APPLE_) 55 | + // flock 56 | + DEF(EINTR), 57 | + DEF(ENOLCK), 58 | + DEF(EWOULDBLOCK) 59 | +#endif /* !_WIN32 && !_APPLE_ */ 60 | + 61 | #undef DEF 62 | }; 63 | 64 | @@ -3026,6 +3059,36 @@ static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val, 65 | } 66 | } 67 | 68 | +#if defined(__linux__) 69 | + int pid = getpid(); 70 | + int max_fd = 0; 71 | + char path[32]; 72 | + struct stat statbuf; 73 | + sprintf(path, "/proc/%d/fd", pid); 74 | + if (stat(path, &statbuf) == 0) { 75 | + if (S_ISDIR(statbuf.st_mode)) { 76 | + DIR *dir = opendir(path); 77 | + if (dir) { 78 | + struct dirent *subdir; 79 | + int fd; 80 | + for(;;) { 81 | + subdir = readdir(dir); 82 | + if (!subdir) { 83 | + break; 84 | + } 85 | + fd = atoi(subdir->d_name); 86 | + if (fd > max_fd) { 87 | + max_fd = fd; 88 | + } 89 | + } 90 | + if (max_fd > 0) { 91 | + fd_max = max_fd; 92 | + } 93 | + closedir(dir); 94 | + } 95 | + } 96 | + } 97 | +#endif 98 | for(i = 3; i < fd_max; i++) 99 | close(i); 100 | if (cwd) { 101 | @@ -3183,6 +3246,73 @@ static JSValue js_os_dup2(JSContext *ctx, JSValueConst this_val, 102 | return JS_NewInt32(ctx, ret); 103 | } 104 | 105 | +#if !defined(_APPLE_) 106 | + 107 | +/* flock(fd, operation) */ 108 | +static JSValue js_os_flock(JSContext *ctx, JSValueConst this_val, 109 | + int argc, JSValueConst *argv) 110 | +{ 111 | + int fd, operation, ret; 112 | + if (JS_ToInt32(ctx, &fd, argv[0])) 113 | + return JS_EXCEPTION; 114 | + if (JS_ToInt32(ctx, &operation, argv[1])) 115 | + return JS_EXCEPTION; 116 | + ret = js_get_errno(flock(fd, operation)); 117 | + return JS_NewInt32(ctx, ret); 118 | +} 119 | + 120 | +/* mkstemp(template, outputObj) */ 121 | +static JSValue js_os_mkstemp(JSContext *ctx, JSValueConst this_val, 122 | + int argc, JSValueConst *argv) 123 | +{ 124 | + char buffer[PATH_MAX]; 125 | + const char *template; 126 | + int ret; 127 | + 128 | + template = JS_ToCString(ctx, argv[0]); 129 | + if (!template) 130 | + return JS_EXCEPTION; 131 | + strncpy(buffer, template, sizeof(buffer)); 132 | + JS_FreeCString(ctx, template); 133 | + ret = js_get_errno(mkstemp(buffer)); 134 | + // check if we can pass the final filename back 135 | + if (argc >= 2 && ret > 0) { 136 | + if (!JS_IsUndefined(argv[1])) { 137 | + JS_SetPropertyStr(ctx, argv[1], "filename", JS_NewString(ctx, buffer)); 138 | + } 139 | + } 140 | + return JS_NewInt32(ctx, ret); 141 | +} 142 | + 143 | +/* mkdtemp(template, errorObj) */ 144 | +static JSValue js_os_mkdtemp(JSContext *ctx, JSValueConst this_val, 145 | + int argc, JSValueConst *argv) 146 | +{ 147 | + char buffer[PATH_MAX]; 148 | + const char *template; 149 | + const char *ptr; 150 | + int err = 0; 151 | + 152 | + template = JS_ToCString(ctx, argv[0]); 153 | + if (!template) 154 | + return JS_EXCEPTION; 155 | + strncpy(buffer, template, sizeof(buffer)); 156 | + JS_FreeCString(ctx, template); 157 | + ptr = mkdtemp(buffer); 158 | + if (NULL == ptr) { 159 | + err = errno; 160 | + } 161 | + if (argc >= 2) { 162 | + js_set_error_object(ctx, argv[1], err); 163 | + } 164 | + if (NULL == ptr) { 165 | + return JS_NULL; 166 | + } 167 | + return JS_NewString(ctx, ptr); 168 | +} 169 | + 170 | +#endif /* !_APPLE_ */ 171 | + 172 | #endif /* !_WIN32 */ 173 | 174 | #ifdef USE_WORKER 175 | @@ -3729,6 +3859,16 @@ static const JSCFunctionListEntry js_os_funcs[] = { 176 | JS_CFUNC_DEF("dup", 1, js_os_dup ), 177 | JS_CFUNC_DEF("dup2", 2, js_os_dup2 ), 178 | #endif 179 | +#if !defined(_WIN32) && !defined(_APPLE_) 180 | + // flock 181 | + JS_CFUNC_DEF("flock", 2, js_os_flock ), 182 | + OS_FLAG(LOCK_EX), 183 | + OS_FLAG(LOCK_NB), 184 | + // mkstemp 185 | + JS_CFUNC_DEF("mkstemp", 1, js_os_mkstemp ), 186 | + // mkdtemp 187 | + JS_CFUNC_DEF("mkdtemp", 1, js_os_mkdtemp ), 188 | +#endif 189 | }; 190 | 191 | static int js_os_init(JSContext *ctx, JSModuleDef *m) 192 | -------------------------------------------------------------------------------- /builder/custom/qjs/patches/2025-04-26/Makefile.patch: -------------------------------------------------------------------------------- 1 | diff --git a/Makefile b/Makefile 2 | index 3b1c745..ad50e54 100644 3 | --- a/Makefile 4 | +++ b/Makefile 5 | @@ -43,7 +43,9 @@ endif 6 | #CONFIG_COSMO=y 7 | 8 | # installation directory 9 | -PREFIX?=/usr/local 10 | +#PREFIX?=/usr/local 11 | +#-- change prefix to / 12 | +PREFIX?=/ 13 | 14 | # use the gprof profiler 15 | #CONFIG_PROFILE=y 16 | @@ -126,7 +128,9 @@ else ifdef CONFIG_COSMO 17 | AR=cosmoar 18 | else 19 | HOST_CC=gcc 20 | - CC=$(CROSS_PREFIX)gcc 21 | + #-- use musl-gcc instead of gcc (symlink must exist) 22 | + #CC=$(CROSS_PREFIX)gcc 23 | + CC=$(CURDIR)/musl-$(musl_arch)/bin/musl-gcc 24 | CFLAGS+=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d 25 | CFLAGS += -Wno-array-bounds -Wno-format-truncation -Wno-infinite-recursion 26 | ifdef CONFIG_LTO 27 | @@ -148,6 +152,8 @@ ifdef CONFIG_WERROR 28 | CFLAGS+=-Werror 29 | endif 30 | DEFINES:=-D_GNU_SOURCE -DCONFIG_VERSION=\"$(shell cat VERSION)\" 31 | +#-- define target architecture 32 | +DEFINES+=-DMUSL_ARCH=\"$(musl_arch)\" 33 | ifdef CONFIG_WIN32 34 | DEFINES+=-D__USE_MINGW_ANSI_STDIO # for standard snprintf behavior 35 | endif 36 | @@ -166,6 +172,10 @@ ifdef CONFIG_COSMO 37 | LDFLAGS+=-s # better to strip by default 38 | else 39 | LDFLAGS+=-g 40 | +#-- force static compilation 41 | +LDFLAGS+=-static 42 | +#-- disable PIE 43 | +CFLAGS+=-no-pie 44 | endif 45 | ifdef CONFIG_LTO 46 | CFLAGS_SMALL+=-flto 47 | @@ -217,6 +227,9 @@ ifdef CONFIG_LTO 48 | PROGS+=libquickjs.lto.a 49 | endif 50 | 51 | +#--when architecture is not 'x86_64', we need to use the 'x86_64' version of the 'qjsc' binary to generate c files 52 | +QJSC_X86_64=$(qjsc_binary) 53 | + 54 | # examples 55 | ifeq ($(CROSS_PREFIX),) 56 | ifndef CONFIG_ASAN 57 | @@ -226,11 +239,13 @@ PROGS+=examples/hello examples/test_fib 58 | # no -m32 option in qjsc 59 | ifndef CONFIG_M32 60 | ifndef CONFIG_WIN32 61 | -PROGS+=examples/hello_module 62 | +#-- disable because of cross-compilation 63 | +#PROGS+=examples/hello_module 64 | endif 65 | endif 66 | ifdef CONFIG_SHARED_LIBS 67 | -PROGS+=examples/fib.so examples/point.so 68 | +#-- disable because of cross-compilation 69 | +#PROGS+=examples/fib.so examples/point.so 70 | endif 71 | endif 72 | endif 73 | @@ -239,7 +254,7 @@ endif 74 | 75 | all: $(OBJDIR) $(OBJDIR)/quickjs.check.o $(OBJDIR)/qjs.check.o $(PROGS) 76 | 77 | -QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/dtoa.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o 78 | +QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/dtoa.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o $(OBJDIR)/path.o 79 | 80 | QJS_OBJS=$(OBJDIR)/qjs.o $(OBJDIR)/repl.o $(QJS_LIB_OBJS) 81 | 82 | @@ -250,6 +265,9 @@ LIBS+=-ldl 83 | endif 84 | LIBS+=$(EXTRA_LIBS) 85 | 86 | +#-- static linking to libatomic (necessary for armv7l) 87 | +LIBS+=-L $(CURDIR)/musl-$(musl_arch)/lib -latomic 88 | + 89 | $(OBJDIR): 90 | mkdir -p $(OBJDIR) $(OBJDIR)/examples $(OBJDIR)/tests 91 | 92 | @@ -308,7 +326,8 @@ libquickjs.fuzz.a: $(patsubst %.o, %.fuzz.o, $(QJS_LIB_OBJS)) 93 | $(AR) rcs $@ $^ 94 | 95 | repl.c: $(QJSC) repl.js 96 | - $(QJSC) -s -c -o $@ -m repl.js 97 | + #-- we use the 'x86_64' version of 'qjsc' when architecture is not 'x86_64' 98 | + $(QJSC_X86_64) -s -c -o $@ -m repl.js 99 | 100 | ifneq ($(wildcard unicode/UnicodeData.txt),) 101 | $(OBJDIR)/libunicode.o $(OBJDIR)/libunicode.nolto.o: libunicode-table.h 102 | @@ -364,9 +383,12 @@ clean: 103 | rm -rf run-test262-debug$(EXE) 104 | rm -f run_octane run_sunspider_like 105 | 106 | -install: all 107 | +#-- only install 108 | +#install: all 109 | +install: 110 | mkdir -p "$(DESTDIR)$(PREFIX)/bin" 111 | - $(STRIP) qjs$(EXE) qjsc$(EXE) 112 | + #-- disable stripping (because of cross-compiling) 113 | + #$(STRIP) qjs$(EXE) qjsc$(EXE) 114 | install -m755 qjs$(EXE) qjsc$(EXE) "$(DESTDIR)$(PREFIX)/bin" 115 | mkdir -p "$(DESTDIR)$(PREFIX)/lib/quickjs" 116 | install -m644 libquickjs.a "$(DESTDIR)$(PREFIX)/lib/quickjs" 117 | @@ -386,7 +408,8 @@ HELLO_OPTS=-fno-string-normalize -fno-map -fno-promise -fno-typedarray \ 118 | -fno-date -fno-module-loader 119 | 120 | hello.c: $(QJSC) $(HELLO_SRCS) 121 | - $(QJSC) -e $(HELLO_OPTS) -o $@ $(HELLO_SRCS) 122 | + #-- we use the 'x86_64' version of 'qjsc' when architecture is not 'x86_64' 123 | + $(QJSC_X86_64) -e $(HELLO_OPTS) -o $@ $(HELLO_SRCS) 124 | 125 | examples/hello: $(OBJDIR)/hello.o $(QJS_LIB_OBJS) 126 | $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) 127 | -------------------------------------------------------------------------------- /builder/custom/qjs/patches/2025-04-26/qjs.patch: -------------------------------------------------------------------------------- 1 | diff --git a/qjs.c b/qjs.c 2 | index 2eaa9ee..f16e2d6 100644 3 | --- a/qjs.c 4 | +++ b/qjs.c 5 | @@ -43,6 +43,8 @@ 6 | #include "cutils.h" 7 | #include "quickjs-libc.h" 8 | 9 | +#include "path.h" 10 | + 11 | extern const uint8_t qjsc_repl[]; 12 | extern const uint32_t qjsc_repl_size; 13 | 14 | @@ -327,6 +329,8 @@ int main(int argc, char **argv) 15 | int strip_flags = 0; 16 | size_t stack_size = 0; 17 | 18 | + set_exe_dir_from_exe_name(argv[0]); 19 | + 20 | /* cannot use getopt because we want to pass the command line to 21 | the script */ 22 | optind = 1; 23 | -------------------------------------------------------------------------------- /builder/custom/qjs/patches/2025-04-26/qjsc.patch: -------------------------------------------------------------------------------- 1 | diff --git a/qjsc.c b/qjsc.c 2 | index f9e1928..e94d00e 100644 3 | --- a/qjsc.c 4 | +++ b/qjsc.c 5 | @@ -36,6 +36,8 @@ 6 | #include "cutils.h" 7 | #include "quickjs-libc.h" 8 | 9 | +#include "path.h" 10 | + 11 | typedef struct { 12 | char *name; 13 | char *short_name; 14 | @@ -253,11 +255,30 @@ JSModuleDef *jsc_module_loader(JSContext *ctx, 15 | char cname[1024]; 16 | 17 | buf = js_load_file(ctx, &buf_len, module_name); 18 | +/* 19 | if (!buf) { 20 | JS_ThrowReferenceError(ctx, "could not load module filename '%s'", 21 | module_name); 22 | return NULL; 23 | } 24 | +*/ 25 | + if (!buf) { 26 | + char path[4096]; 27 | + // check if a custom lib dir has been defined 28 | + char* lib_dir = getenv("QJS_LIB_DIR"); 29 | + if (NULL == lib_dir) { 30 | + get_path_with_exe_dir(path, sizeof(path), (char*)module_name); 31 | + } 32 | + else { 33 | + get_path_with_dir(path, sizeof(path), lib_dir, (char*)module_name); 34 | + } 35 | + buf = js_load_file(ctx, &buf_len, path); 36 | + if (!buf) { 37 | + JS_ThrowReferenceError(ctx, "could not load module filename '%s'", 38 | + module_name); 39 | + return NULL; 40 | + } 41 | + } 42 | 43 | /* compile the module */ 44 | func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name, 45 | @@ -401,6 +422,8 @@ static int output_executable(const char *out_filename, const char *cfilename, 46 | const char **arg, *bn_suffix, *lto_suffix; 47 | char libjsname[1024]; 48 | char exe_dir[1024], inc_dir[1024], lib_dir[1024], buf[1024], *p; 49 | + //-- used to store relative path to musl-gcc 50 | + char musl_gcc[4096]; 51 | int ret; 52 | 53 | /* get the directory of the executable */ 54 | @@ -427,8 +450,15 @@ static int output_executable(const char *out_filename, const char *cfilename, 55 | bn_suffix = ""; 56 | 57 | arg = argv; 58 | - *arg++ = CONFIG_CC; 59 | + //-- use included musl-gcc wrapper instead of default compiler 60 | + //*arg++ = CONFIG_CC; 61 | + snprintf(musl_gcc, sizeof(musl_gcc), "%s/musl-%s/bin/musl-gcc", exe_dir, MUSL_ARCH); 62 | + *arg++ = musl_gcc; 63 | *arg++ = "-O2"; 64 | + //-- force static compilation 65 | + *arg++ = "-static"; 66 | + //-- strip 67 | + *arg++ = "-s"; 68 | #ifdef CONFIG_LTO 69 | if (use_lto) { 70 | *arg++ = "-flto"; 71 | @@ -452,6 +482,8 @@ static int output_executable(const char *out_filename, const char *cfilename, 72 | *arg++ = "-lm"; 73 | *arg++ = "-ldl"; 74 | *arg++ = "-lpthread"; 75 | + //-- link to libatomic (armv7l) 76 | + *arg++ = "-latomic"; 77 | *arg = NULL; 78 | 79 | if (verbose) { 80 | @@ -462,6 +494,22 @@ static int output_executable(const char *out_filename, const char *cfilename, 81 | 82 | ret = exec_cmd((char **)argv); 83 | unlink(cfilename); 84 | + //-- compress executable using upx 85 | + if (0 == ret) { 86 | + p = getenv("QJS_UPX"); 87 | + if (NULL != p && 0 == strcmp(p, "1")) { 88 | + arg = argv; 89 | + *arg++ = "upx"; 90 | + *arg++ = out_filename; 91 | + *arg = NULL; 92 | + if (verbose) { 93 | + for(arg = argv; *arg != NULL; arg++) 94 | + printf("%s ", *arg); 95 | + printf("\n"); 96 | + } 97 | + exec_cmd((char **)argv); 98 | + } 99 | + } 100 | return ret; 101 | } 102 | #else 103 | @@ -551,6 +599,8 @@ int main(int argc, char **argv) 104 | namelist_add(&cmodule_list, "std", "std", 0); 105 | namelist_add(&cmodule_list, "os", "os", 0); 106 | 107 | + set_exe_dir_from_exe_name(argv[0]); 108 | + 109 | optind = 1; 110 | while (optind < argc && *argv[optind] == '-') { 111 | char *arg = argv[optind] + 1; 112 | -------------------------------------------------------------------------------- /builder/custom/qjs/patches/2025-04-26/quickjs-libc.patch: -------------------------------------------------------------------------------- 1 | diff --git a/quickjs-libc.c b/quickjs-libc.c 2 | index 0788d8c..27919c3 100644 3 | --- a/quickjs-libc.c 4 | +++ b/quickjs-libc.c 5 | @@ -76,10 +76,17 @@ typedef sig_t sighandler_t; 6 | #include "list.h" 7 | #include "quickjs-libc.h" 8 | 9 | +#include "path.h" 10 | + 11 | #if !defined(PATH_MAX) 12 | #define PATH_MAX 4096 13 | #endif 14 | 15 | +#if !defined(_WIN32) && !defined(__APPLE__) 16 | +// flock 17 | +#include 18 | +#endif /* !_WIN32 && !_APPLE_ 19 | + 20 | /* TODO: 21 | - add socket calls 22 | */ 23 | @@ -596,11 +603,30 @@ JSModuleDef *js_module_loader(JSContext *ctx, 24 | JSValue func_val; 25 | 26 | buf = js_load_file(ctx, &buf_len, module_name); 27 | +/* 28 | if (!buf) { 29 | JS_ThrowReferenceError(ctx, "could not load module filename '%s'", 30 | module_name); 31 | return NULL; 32 | } 33 | +*/ 34 | + if (!buf) { 35 | + char path[4096]; 36 | + // check if a custom lib dir has been defined 37 | + char* lib_dir = getenv("QJS_LIB_DIR"); 38 | + if (NULL == lib_dir) { 39 | + get_path_with_exe_dir(path, sizeof(path), (char*)module_name); 40 | + } 41 | + else { 42 | + get_path_with_dir(path, sizeof(path), lib_dir, (char*)module_name); 43 | + } 44 | + buf = js_load_file(ctx, &buf_len, path); 45 | + if (!buf) { 46 | + JS_ThrowReferenceError(ctx, "could not load module filename '%s'", 47 | + module_name); 48 | + return NULL; 49 | + } 50 | + } 51 | 52 | /* compile the module */ 53 | func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name, 54 | @@ -1511,6 +1537,12 @@ static const JSCFunctionListEntry js_std_error_props[] = { 55 | DEF(EPERM), 56 | DEF(EPIPE), 57 | DEF(EBADF), 58 | +#if !defined(_WIN32) && !defined(_APPLE_) 59 | + // flock 60 | + DEF(EINTR), 61 | + DEF(ENOLCK), 62 | + DEF(EWOULDBLOCK) 63 | +#endif /* !_WIN32 && !_APPLE_ */ 64 | #undef DEF 65 | }; 66 | 67 | @@ -3112,6 +3144,7 @@ static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val, 68 | } 69 | if (pid == 0) { 70 | /* child */ 71 | + int fd_max = sysconf(_SC_OPEN_MAX); 72 | 73 | /* remap the stdin/stdout/stderr handles if necessary */ 74 | for(i = 0; i < 3; i++) { 75 | @@ -3120,28 +3153,39 @@ static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val, 76 | _exit(127); 77 | } 78 | } 79 | -#if defined(HAVE_CLOSEFROM) 80 | - /* closefrom() is available on many recent unix systems: 81 | - Linux with glibc 2.34+, Solaris 9+, FreeBSD 7.3+, 82 | - NetBSD 3.0+, OpenBSD 3.5+. 83 | - Linux with the musl libc and macOS don't have it. 84 | - */ 85 | - 86 | - closefrom(3); 87 | -#else 88 | - { 89 | - /* Close the file handles manually, limit to 1024 to avoid 90 | - costly loop on linux Alpine where sysconf(_SC_OPEN_MAX) 91 | - returns a huge value 1048576. 92 | - Patch inspired by nicolas-duteil-nova. See also: 93 | - https://stackoverflow.com/questions/73229353/ 94 | - https://stackoverflow.com/questions/899038/#918469 95 | - */ 96 | - int fd_max = min_int(sysconf(_SC_OPEN_MAX), 1024); 97 | - for(i = 3; i < fd_max; i++) 98 | - close(i); 99 | + 100 | +#if defined(__linux__) 101 | + int pid = getpid(); 102 | + int max_fd = 0; 103 | + char path[32]; 104 | + struct stat statbuf; 105 | + sprintf(path, "/proc/%d/fd", pid); 106 | + if (stat(path, &statbuf) == 0) { 107 | + if (S_ISDIR(statbuf.st_mode)) { 108 | + DIR *dir = opendir(path); 109 | + if (dir) { 110 | + struct dirent *subdir; 111 | + int fd; 112 | + for(;;) { 113 | + subdir = readdir(dir); 114 | + if (!subdir) { 115 | + break; 116 | + } 117 | + fd = atoi(subdir->d_name); 118 | + if (fd > max_fd) { 119 | + max_fd = fd; 120 | + } 121 | + } 122 | + if (max_fd > 0) { 123 | + fd_max = max_fd; 124 | + } 125 | + closedir(dir); 126 | + } 127 | + } 128 | } 129 | #endif 130 | + for(i = 3; i < fd_max; i++) 131 | + close(i); 132 | if (cwd) { 133 | if (chdir(cwd) < 0) 134 | _exit(127); 135 | @@ -3296,6 +3340,72 @@ static JSValue js_os_dup2(JSContext *ctx, JSValueConst this_val, 136 | ret = js_get_errno(dup2(fd, fd2)); 137 | return JS_NewInt32(ctx, ret); 138 | } 139 | +#if !defined(_APPLE_) 140 | + 141 | +/* flock(fd, operation) */ 142 | +static JSValue js_os_flock(JSContext *ctx, JSValueConst this_val, 143 | + int argc, JSValueConst *argv) 144 | +{ 145 | + int fd, operation, ret; 146 | + if (JS_ToInt32(ctx, &fd, argv[0])) 147 | + return JS_EXCEPTION; 148 | + if (JS_ToInt32(ctx, &operation, argv[1])) 149 | + return JS_EXCEPTION; 150 | + ret = js_get_errno(flock(fd, operation)); 151 | + return JS_NewInt32(ctx, ret); 152 | +} 153 | + 154 | +/* mkstemp(template, outputObj) */ 155 | +static JSValue js_os_mkstemp(JSContext *ctx, JSValueConst this_val, 156 | + int argc, JSValueConst *argv) 157 | +{ 158 | + char buffer[PATH_MAX]; 159 | + const char *template; 160 | + int ret; 161 | + 162 | + template = JS_ToCString(ctx, argv[0]); 163 | + if (!template) 164 | + return JS_EXCEPTION; 165 | + strncpy(buffer, template, sizeof(buffer)); 166 | + JS_FreeCString(ctx, template); 167 | + ret = js_get_errno(mkstemp(buffer)); 168 | + // check if we can pass the final filename back 169 | + if (argc >= 2 && ret > 0) { 170 | + if (!JS_IsUndefined(argv[1])) { 171 | + JS_SetPropertyStr(ctx, argv[1], "filename", JS_NewString(ctx, buffer)); 172 | + } 173 | + } 174 | + return JS_NewInt32(ctx, ret); 175 | +} 176 | + 177 | +/* mkdtemp(template, errorObj) */ 178 | +static JSValue js_os_mkdtemp(JSContext *ctx, JSValueConst this_val, 179 | + int argc, JSValueConst *argv) 180 | +{ 181 | + char buffer[PATH_MAX]; 182 | + const char *template; 183 | + const char *ptr; 184 | + int err = 0; 185 | + 186 | + template = JS_ToCString(ctx, argv[0]); 187 | + if (!template) 188 | + return JS_EXCEPTION; 189 | + strncpy(buffer, template, sizeof(buffer)); 190 | + JS_FreeCString(ctx, template); 191 | + ptr = mkdtemp(buffer); 192 | + if (NULL == ptr) { 193 | + err = errno; 194 | + } 195 | + if (argc >= 2) { 196 | + js_set_error_object(ctx, argv[1], err); 197 | + } 198 | + if (NULL == ptr) { 199 | + return JS_NULL; 200 | + } 201 | + return JS_NewString(ctx, ptr); 202 | +} 203 | + 204 | +#endif /* !_APPLE_ */ 205 | 206 | #endif /* !_WIN32 */ 207 | 208 | @@ -3834,6 +3944,16 @@ static const JSCFunctionListEntry js_os_funcs[] = { 209 | JS_CFUNC_DEF("dup", 1, js_os_dup ), 210 | JS_CFUNC_DEF("dup2", 2, js_os_dup2 ), 211 | #endif 212 | +#if !defined(_WIN32) && !defined(_APPLE_) 213 | + // flock 214 | + JS_CFUNC_DEF("flock", 2, js_os_flock ), 215 | + OS_FLAG(LOCK_EX), 216 | + OS_FLAG(LOCK_NB), 217 | + // mkstemp 218 | + JS_CFUNC_DEF("mkstemp", 1, js_os_mkstemp ), 219 | + // mkdtemp 220 | + JS_CFUNC_DEF("mkdtemp", 1, js_os_mkdtemp ), 221 | +#endif 222 | }; 223 | 224 | static int js_os_init(JSContext *ctx, JSModuleDef *m) 225 | -------------------------------------------------------------------------------- /builder/custom/qjs/qjsc-x86_64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctn-malone/quickjs-cross-compiler/36bc7985737c6b3e9e4701e2d369dfa17ed96c0b/builder/custom/qjs/qjsc-x86_64 -------------------------------------------------------------------------------- /builder/custom/qjs/scripts/examples/compile_examples.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ### 4 | # 5 | # Compile all .js sources in this directory 6 | # 7 | ### 8 | 9 | script_dir="$(cd "$(dirname "$(readlink -f "$0")")" && pwd)" 10 | # compile binaries 11 | for js_file in $(ls ${script_dir}/*.js) 12 | do 13 | echo "Compiling '${js_file}'..." 14 | filename="$(basename ${js_file} .js)" 15 | binary_file="${script_dir}/${filename}" 16 | ${script_dir}/../qjsc.sh -o ${binary_file} ${js_file} || exit 1 17 | done 18 | # compile binaries for ext-lib 19 | if [ -d ${script_dir}/ext-lib ] 20 | then 21 | for js_file in $(ls ${script_dir}/ext-lib/*.js) 22 | do 23 | echo "Compiling '${js_file}'..." 24 | filename="$(basename ${js_file} .js)" 25 | binary_file="${script_dir}/ext-lib/${filename}" 26 | ${script_dir}/../qjsc.sh -o ${binary_file} ${js_file} || exit 1 27 | done 28 | fi 29 | -------------------------------------------------------------------------------- /builder/custom/qjs/scripts/qjs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ### 4 | # 5 | # This script should be use if you want to symlink 'qjs' binary 6 | # When using a direct symlink, import of js files located in the 7 | # directory containing 'qjs' binary will fail since 'qjs' binary 8 | # won't be able to find includes & libraries 9 | # 10 | # Using an intermediate shell script ensure symlink is correctly 11 | # resolved 12 | # 13 | ### 14 | 15 | # ensure we're returning exit code from child process 16 | trap ignore 2 17 | 18 | ignore() { 19 | : 20 | } 21 | 22 | script_dir="$(cd "$(dirname "$(readlink -f "$0")")" && pwd)" 23 | ${script_dir}/qjs "$@" 24 | -------------------------------------------------------------------------------- /builder/custom/qjs/scripts/qjsc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ### 4 | # 5 | # This script should be use if you want to symlink 'qjsc' binary 6 | # When using a direct symlink, compilation will fail since 'qjsc' 7 | # won't be able to find includes & libraries 8 | # 9 | # Using an intermediate shell script ensure symlink is correctly 10 | # resolved 11 | # 12 | ### 13 | 14 | # if variable is not defined yet, check if upx is available 15 | if [ -z ${QJS_UPX} ] 16 | then 17 | upx=$(command -v upx) 18 | if ! [ -z ${upx} ] 19 | then 20 | QJS_UPX=1 21 | fi 22 | fi 23 | script_dir="$(cd "$(dirname "$(readlink -f "$0")")" && pwd)" 24 | QJS_UPX=${QJS_UPX} ${script_dir}/qjsc "$@" 25 | -------------------------------------------------------------------------------- /builder/env/deps: -------------------------------------------------------------------------------- 1 | # musl library 2 | declare -A cfg_musl_lib=( 3 | ["archive_url"]="https://musl.libc.org/releases/musl-1.2.2.tar.gz" 4 | ["archive_dir"]="musl-1.2.2" 5 | ["archive_dir_symlink"]="musl" 6 | ) 7 | 8 | # musl.cc cross-compiler for x86_64 target 9 | declare -A cfg_musl_cc_x86_64=( 10 | #["archive_url"]="https://more.musl.cc/10.2.1/x86_64-linux-musl/x86_64-linux-musl-cross.tgz" 11 | ["archive_url"]="https://github.com/ctn-malone/musl-cross-maker/releases/download/gcc-6.5.0_binutils-2.25.1_musl-1.2.2/x86_64-linux-musl-cross.tgz" 12 | ["archive_dir"]="x86_64-linux-musl-cross" 13 | ["archive_dir_symlink"]="musl_cc-x86_64" 14 | ) 15 | 16 | # musl.cc cross-compiler for i686 target 17 | declare -A cfg_musl_cc_i686=( 18 | #["archive_url"]="https://more.musl.cc/10.2.1/x86_64-linux-musl/i686-linux-musl-cross.tgz" 19 | ["archive_url"]="https://github.com/ctn-malone/musl-cross-maker/releases/download/gcc-6.5.0_binutils-2.25.1_musl-1.2.2/i686-linux-musl-cross.tgz" 20 | ["archive_dir"]="i686-linux-musl-cross" 21 | ["archive_dir_symlink"]="musl_cc-i686" 22 | ) 23 | 24 | # musl.cc cross-compiler for armv7l target 25 | declare -A cfg_musl_cc_armv7l=( 26 | #["archive_url"]="https://more.musl.cc/10.2.1/x86_64-linux-musl/armv7l-linux-musleabihf-cross.tgz" 27 | ["archive_url"]="https://github.com/ctn-malone/musl-cross-maker/releases/download/gcc-6.5.0_binutils-2.25.1_musl-1.2.2/armv7l-linux-musleabihf-cross.tgz" 28 | ["archive_dir"]="armv7l-linux-musleabihf-cross" 29 | ["archive_dir_symlink"]="musl_cc-armv7l" 30 | ) 31 | 32 | # musl.cc cross-compiler for aarch64 target 33 | declare -A cfg_musl_cc_aarch64=( 34 | #["archive_url"]="https://more.musl.cc/10.2.1/x86_64-linux-musl/aarch64-linux-musl-cross.tgz" 35 | ["archive_url"]="https://github.com/ctn-malone/musl-cross-maker/releases/download/gcc-6.5.0_binutils-2.25.1_musl-1.2.2/aarch64-linux-musl-cross.tgz" 36 | ["archive_dir"]="aarch64-linux-musl-cross" 37 | ["archive_dir_symlink"]="musl_cc-aarch64" 38 | ) 39 | -------------------------------------------------------------------------------- /builder/env/qjs: -------------------------------------------------------------------------------- 1 | # QuickJS repository to clone 2 | qjs_repository="https://github.com/bellard/quickjs.git" 3 | 4 | default_qjs_version="2025-04-26" 5 | 6 | # mapping qjs version => commit id 7 | declare -A qjs_commits=( 8 | ["2020-09-06"]="7c312df422572cf867f29a1d80693e8a77f7fb2a" 9 | ["2020-11-08"]="204682fb87ab9312f0cf81f959ecd181180457bc" 10 | ["2021-03-27"]="b5e62895c619d4ffc75c9d822c8d85f1ece77e5b" 11 | ["2023-12-09"]="daa35bc1e5d43192098af9b51caeb4f18f73f9f9" 12 | ["2024-01-13"]="3f81070e573e3592728dbbbd04c84c498b20d6dc" 13 | ["2025-04-26"]="19abf1888db5884a5758036ff6e7fa2b340acedc" 14 | ) 15 | 16 | # mapping qjs version => package name 17 | declare -A qjs_packages=( 18 | ["2020-09-06"]="2020-09-06" 19 | ["2020-11-08"]="2020-11-08_3" 20 | ["2021-03-27"]="2021-03-27_4" 21 | ["2023-12-09"]="2023-12-09_1" 22 | ["2024-01-13"]="2024-01-13_3" 23 | ["2025-04-26"]="2025-04-26_1" 24 | ) 25 | 26 | # default tag for https://github.com/ctn-malone/qjs-ext-lib 27 | qjs_ext_lib_repository="https://github.com/ctn-malone/qjs-ext-lib" 28 | default_qjs_ext_lib_version="0.14.2" 29 | -------------------------------------------------------------------------------- /builder/scripts/bootstrap-alpine.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ### 4 | # 5 | # Used to install necessary Alpine packages (only needed when building under Alpine) 6 | # 7 | ### 8 | 9 | apk add build-base xz bash git curl upx 10 | -------------------------------------------------------------------------------- /builder/scripts/build_deps.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### 4 | # 5 | # Build dependencies 6 | # - compile musl lib for a specific architecture 7 | # - strip static libraries 8 | # - copy some static libraries from the musl-cc tree 9 | # - copy musl-gcc wrapper & specs 10 | # 11 | ### 12 | 13 | script_dir="$(cd "$(dirname "$(readlink -f "$0")")" && pwd)" || { echo "Couldn't determine the script's running directory, which probably matters, bailing out" >&2; exit 2; } 14 | source "${script_dir}/../env/qjs" 15 | 16 | # Created by argbash-init v2.10.0 17 | # ARG_OPTIONAL_SINGLE([deps-dir],[d],[directory containing dependencies],[$script_dir/../../deps]) 18 | # ARG_OPTIONAL_SINGLE([arch],[a],[target architecture],[x86_64]) 19 | # ARG_OPTIONAL_BOOLEAN([force],[f],[force rebuild],[off]) 20 | # ARG_OPTIONAL_BOOLEAN([verbose],[v],[enable verbose mode],[off]) 21 | # ARG_TYPE_GROUP_SET([arch],[type string],[arch],[x86_64,i686,armv7l,aarch64]) 22 | # ARG_HELP([Build dependencies needed to build a static version of QuickJS]) 23 | # ARGBASH_GO() 24 | # needed because of Argbash --> m4_ignore([ 25 | ### START OF CODE GENERATED BY Argbash v2.10.0 one line above ### 26 | # Argbash is a bash code generator used to get arguments parsing right. 27 | # Argbash is FREE SOFTWARE, see https://argbash.io for more info 28 | 29 | 30 | die() 31 | { 32 | local _ret="${2:-1}" 33 | test "${_PRINT_HELP:-no}" = yes && print_help >&2 34 | echo "$1" >&2 35 | exit "${_ret}" 36 | } 37 | 38 | # validators 39 | 40 | arch() 41 | { 42 | local _allowed=("x86_64" "i686" "armv7l" "aarch64") _seeking="$1" 43 | for element in "${_allowed[@]}" 44 | do 45 | test "$element" = "$_seeking" && echo "$element" && return 0 46 | done 47 | die "Value '$_seeking' (of argument '$2') doesn't match the list of allowed values: 'x86_64', 'i686', 'armv7l' and 'aarch64'" 4 48 | } 49 | 50 | 51 | begins_with_short_option() 52 | { 53 | local first_option all_short_options='dafvh' 54 | first_option="${1:0:1}" 55 | test "$all_short_options" = "${all_short_options/$first_option/}" && return 1 || return 0 56 | } 57 | 58 | # THE DEFAULTS INITIALIZATION - OPTIONALS 59 | _arg_deps_dir="$script_dir/../../deps" 60 | _arg_arch="x86_64" 61 | _arg_force="off" 62 | _arg_verbose="off" 63 | 64 | 65 | print_help() 66 | { 67 | printf '%s\n' "Build dependencies needed to build a static version of QuickJS" 68 | printf 'Usage: %s [-d|--deps-dir ] [-a|--arch ] [-f|--(no-)force] [-v|--(no-)verbose] [-h|--help]\n' "$0" 69 | printf '\t%s\n' "-d, --deps-dir: directory containing dependencies (default: '$script_dir/../../deps')" 70 | printf '\t%s\n' "-a, --arch: target architecture. Can be one of: 'x86_64', 'i686', 'armv7l' and 'aarch64' (default: 'x86_64')" 71 | printf '\t%s\n' "-f, --force, --no-force: force rebuild (off by default)" 72 | printf '\t%s\n' "-v, --verbose, --no-verbose: enable verbose mode (off by default)" 73 | printf '\t%s\n' "-h, --help: Prints help" 74 | } 75 | 76 | 77 | parse_commandline() 78 | { 79 | while test $# -gt 0 80 | do 81 | _key="$1" 82 | case "$_key" in 83 | -d|--deps-dir) 84 | test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 85 | _arg_deps_dir="$2" 86 | shift 87 | ;; 88 | --deps-dir=*) 89 | _arg_deps_dir="${_key##--deps-dir=}" 90 | ;; 91 | -d*) 92 | _arg_deps_dir="${_key##-d}" 93 | ;; 94 | -a|--arch) 95 | test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 96 | _arg_arch="$(arch "$2" "arch")" || exit 1 97 | shift 98 | ;; 99 | --arch=*) 100 | _arg_arch="$(arch "${_key##--arch=}" "arch")" || exit 1 101 | ;; 102 | -a*) 103 | _arg_arch="$(arch "${_key##-a}" "arch")" || exit 1 104 | ;; 105 | -f|--no-force|--force) 106 | _arg_force="on" 107 | test "${1:0:5}" = "--no-" && _arg_force="off" 108 | ;; 109 | -f*) 110 | _arg_force="on" 111 | _next="${_key##-f}" 112 | if test -n "$_next" -a "$_next" != "$_key" 113 | then 114 | { begins_with_short_option "$_next" && shift && set -- "-f" "-${_next}" "$@"; } || die "The short option '$_key' can't be decomposed to ${_key:0:2} and -${_key:2}, because ${_key:0:2} doesn't accept value and '-${_key:2:1}' doesn't correspond to a short option." 115 | fi 116 | ;; 117 | -v|--no-verbose|--verbose) 118 | _arg_verbose="on" 119 | test "${1:0:5}" = "--no-" && _arg_verbose="off" 120 | ;; 121 | -v*) 122 | _arg_verbose="on" 123 | _next="${_key##-v}" 124 | if test -n "$_next" -a "$_next" != "$_key" 125 | then 126 | { begins_with_short_option "$_next" && shift && set -- "-v" "-${_next}" "$@"; } || die "The short option '$_key' can't be decomposed to ${_key:0:2} and -${_key:2}, because ${_key:0:2} doesn't accept value and '-${_key:2:1}' doesn't correspond to a short option." 127 | fi 128 | ;; 129 | -h|--help) 130 | print_help 131 | exit 0 132 | ;; 133 | -h*) 134 | print_help 135 | exit 0 136 | ;; 137 | *) 138 | _PRINT_HELP=yes die "FATAL ERROR: Got an unexpected argument '$1'" 1 139 | ;; 140 | esac 141 | shift 142 | done 143 | } 144 | 145 | parse_commandline "$@" 146 | 147 | # OTHER STUFF GENERATED BY Argbash 148 | # Validation of values 149 | 150 | 151 | ### END OF CODE GENERATED BY Argbash (sortof) ### ]) 152 | # [ <-- needed because of Argbash 153 | 154 | 155 | # vvv PLACE YOUR CODE HERE vvv 156 | 157 | source "${script_dir}/../env/deps" 158 | 159 | # build 'musl lib' 160 | build_musl_lib() 161 | { 162 | [ ${_arg_verbose} == "on" ] && echo "Building 'musl lib' for '${_arg_arch}'..." 163 | 164 | declare -n _cfg="cfg_musl_lib" 165 | 166 | # directory containing 'musl' sources 167 | _archive_dir="${deps_dir}/${_cfg["archive_dir_symlink"]}" 168 | # directory where built library will be installed 169 | _build_dir="${_archive_dir}/BUILD-${_arg_arch}" 170 | # used to keep track of whether or not library was built 171 | _built_marker="${_archive_dir}/.built-${_arg_arch}" 172 | # compiler binary 173 | _cc="${deps_dir}/musl_cc-${_arg_arch}/cc" 174 | # library which will be copied from 'musl_cc' directory (required for 'armv7l' compilation) 175 | _libatomic="${deps_dir}/musl_cc-${_arg_arch}/libatomic.a" 176 | # library which will be copied from 'musl_cc' directory (to avoid linking error 'cannot find -lssp_nonshared' on alpine) 177 | _libssp_nonshared="${deps_dir}/musl_cc-${_arg_arch}/libssp_nonshared.a" 178 | # use 'strip' binary from cross compiler 179 | _strip="${deps_dir}/musl_cc-${_arg_arch}/strip" 180 | # directory containing custom files which will be copied after build 181 | _custom_dir="${custom_dir}/musl" 182 | 183 | # ensure all dependencies exist 184 | if ! [ -d ${_archive_dir} ] || ! [ -f ${_cc} ] 185 | then 186 | echo "Missing dependencies. Run 'fetch_deps.sh' script first" 1>&2 187 | return 1 188 | fi 189 | 190 | # already built 191 | if [ -f ${_built_marker} ] && [ ${_arg_force} == "off" ] 192 | then 193 | [ ${_arg_verbose} == "on" ] && echo "No need to build 'musl lib' for '${_arg_arch}'" 194 | else 195 | # build 196 | (rm -f ${_built_marker} && \ 197 | rm -fr ${_build_dir} && \ 198 | cd ${_archive_dir} && \ 199 | make clean && \ 200 | CC=${_cc} LDFLAGS=-s ./configure --disable-shared \ 201 | --prefix=/ \ 202 | --syslibdir=/lib \ 203 | --exec-prefix=/ \ 204 | --enable-wrapper=no && \ 205 | DESTDIR=${_build_dir} make install) || return 1 206 | [ ${_arg_verbose} == "on" ] && echo "Successfully built 'musl lib' for '${_arg_arch}'" 207 | fi 208 | 209 | # copy script & specs 210 | cp -R ${_custom_dir}/* ${_build_dir} || return 1 211 | 212 | # copy 'libatomic' from musl-cc 213 | cp -L ${_libatomic} ${_build_dir}/lib || return 1 214 | 215 | # copy 'libssp_nonshared' from musl-cc 216 | cp -L ${_libssp_nonshared} ${_build_dir}/lib || return 1 217 | 218 | # strip all static libraries 219 | for _file in $(find "${_build_dir}/" -type f -name '*.a') 220 | do 221 | ${_strip} -d ${_file} || return 1 222 | done 223 | 224 | # create build marker 225 | touch ${_built_marker} || return 1 226 | 227 | return 0 228 | } 229 | 230 | # build all dependencies 231 | build_deps() 232 | { 233 | [ ${_arg_verbose} == "on" ] && echo "Building dependencies for '${_arg_arch}'..." 234 | 235 | build_musl_lib || return 1 236 | 237 | [ ${_arg_verbose} == "on" ] && echo "Dependencies for '${_arg_arch}' successfully built" 238 | 239 | return 0 240 | } 241 | 242 | _PRINT_HELP=no 243 | deps_dir=${_arg_deps_dir} 244 | custom_dir="${script_dir}/../custom" 245 | 246 | build_deps || die "Could not build dependencies for '${_arg_arch}'" 247 | 248 | # ^^^ TERMINATE YOUR CODE BEFORE THE BOTTOM ARGBASH MARKER ^^^ 249 | 250 | # ] <-- needed because of Argbash 251 | -------------------------------------------------------------------------------- /builder/scripts/build_qjs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### 4 | # 5 | # Compile QuickJS 6 | # - compile interpreter & compiler statically 7 | # 8 | ### 9 | 10 | script_dir="$(cd "$(dirname "$(readlink -f "$0")")" && pwd)" || { echo "Couldn't determine the script's running directory, which probably matters, bailing out" >&2; exit 2; } 11 | source "${script_dir}/../env/qjs" 12 | 13 | # Created by argbash-init v2.10.0 14 | # ARG_OPTIONAL_SINGLE([deps-dir],[d],[directory containing dependencies],[$script_dir/../../deps]) 15 | # ARG_OPTIONAL_SINGLE([arch],[a],[target architecture],[x86_64]) 16 | # ARG_OPTIONAL_BOOLEAN([force],[f],[force rebuild],[off]) 17 | # ARG_OPTIONAL_BOOLEAN([verbose],[v],[enable verbose mode],[off]) 18 | # ARG_POSITIONAL_SINGLE([qjs-version],[QuickJS version (ex: 2020-09-06)],[$default_qjs_version]) 19 | # ARG_TYPE_GROUP_SET([arch],[type string],[arch],[x86_64,i686,armv7l,aarch64]) 20 | # ARG_HELP([Build a static version of QuickJS (interpreter & compiler)]) 21 | # ARGBASH_GO() 22 | # needed because of Argbash --> m4_ignore([ 23 | ### START OF CODE GENERATED BY Argbash v2.10.0 one line above ### 24 | # Argbash is a bash code generator used to get arguments parsing right. 25 | # Argbash is FREE SOFTWARE, see https://argbash.io for more info 26 | 27 | 28 | die() 29 | { 30 | local _ret="${2:-1}" 31 | test "${_PRINT_HELP:-no}" = yes && print_help >&2 32 | echo "$1" >&2 33 | exit "${_ret}" 34 | } 35 | 36 | # validators 37 | 38 | arch() 39 | { 40 | local _allowed=("x86_64" "i686" "armv7l" "aarch64") _seeking="$1" 41 | for element in "${_allowed[@]}" 42 | do 43 | test "$element" = "$_seeking" && echo "$element" && return 0 44 | done 45 | die "Value '$_seeking' (of argument '$2') doesn't match the list of allowed values: 'x86_64', 'i686', 'armv7l' and 'aarch64'" 4 46 | } 47 | 48 | 49 | begins_with_short_option() 50 | { 51 | local first_option all_short_options='dafvh' 52 | first_option="${1:0:1}" 53 | test "$all_short_options" = "${all_short_options/$first_option/}" && return 1 || return 0 54 | } 55 | 56 | # THE DEFAULTS INITIALIZATION - POSITIONALS 57 | _positionals=() 58 | _arg_qjs_version="$default_qjs_version" 59 | # THE DEFAULTS INITIALIZATION - OPTIONALS 60 | _arg_deps_dir="$script_dir/../../deps" 61 | _arg_arch="x86_64" 62 | _arg_force="off" 63 | _arg_verbose="off" 64 | 65 | 66 | print_help() 67 | { 68 | printf '%s\n' "Build a static version of QuickJS (interpreter & compiler)" 69 | printf 'Usage: %s [-d|--deps-dir ] [-a|--arch ] [-f|--(no-)force] [-v|--(no-)verbose] [-h|--help] []\n' "$0" 70 | printf '\t%s\n' ": QuickJS version (ex: 2020-09-06) (default: '$default_qjs_version')" 71 | printf '\t%s\n' "-d, --deps-dir: directory containing dependencies (default: '$script_dir/../../deps')" 72 | printf '\t%s\n' "-a, --arch: target architecture. Can be one of: 'x86_64', 'i686', 'armv7l' and 'aarch64' (default: 'x86_64')" 73 | printf '\t%s\n' "-f, --force, --no-force: force rebuild (off by default)" 74 | printf '\t%s\n' "-v, --verbose, --no-verbose: enable verbose mode (off by default)" 75 | printf '\t%s\n' "-h, --help: Prints help" 76 | } 77 | 78 | 79 | parse_commandline() 80 | { 81 | _positionals_count=0 82 | while test $# -gt 0 83 | do 84 | _key="$1" 85 | case "$_key" in 86 | -d|--deps-dir) 87 | test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 88 | _arg_deps_dir="$2" 89 | shift 90 | ;; 91 | --deps-dir=*) 92 | _arg_deps_dir="${_key##--deps-dir=}" 93 | ;; 94 | -d*) 95 | _arg_deps_dir="${_key##-d}" 96 | ;; 97 | -a|--arch) 98 | test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 99 | _arg_arch="$(arch "$2" "arch")" || exit 1 100 | shift 101 | ;; 102 | --arch=*) 103 | _arg_arch="$(arch "${_key##--arch=}" "arch")" || exit 1 104 | ;; 105 | -a*) 106 | _arg_arch="$(arch "${_key##-a}" "arch")" || exit 1 107 | ;; 108 | -f|--no-force|--force) 109 | _arg_force="on" 110 | test "${1:0:5}" = "--no-" && _arg_force="off" 111 | ;; 112 | -f*) 113 | _arg_force="on" 114 | _next="${_key##-f}" 115 | if test -n "$_next" -a "$_next" != "$_key" 116 | then 117 | { begins_with_short_option "$_next" && shift && set -- "-f" "-${_next}" "$@"; } || die "The short option '$_key' can't be decomposed to ${_key:0:2} and -${_key:2}, because ${_key:0:2} doesn't accept value and '-${_key:2:1}' doesn't correspond to a short option." 118 | fi 119 | ;; 120 | -v|--no-verbose|--verbose) 121 | _arg_verbose="on" 122 | test "${1:0:5}" = "--no-" && _arg_verbose="off" 123 | ;; 124 | -v*) 125 | _arg_verbose="on" 126 | _next="${_key##-v}" 127 | if test -n "$_next" -a "$_next" != "$_key" 128 | then 129 | { begins_with_short_option "$_next" && shift && set -- "-v" "-${_next}" "$@"; } || die "The short option '$_key' can't be decomposed to ${_key:0:2} and -${_key:2}, because ${_key:0:2} doesn't accept value and '-${_key:2:1}' doesn't correspond to a short option." 130 | fi 131 | ;; 132 | -h|--help) 133 | print_help 134 | exit 0 135 | ;; 136 | -h*) 137 | print_help 138 | exit 0 139 | ;; 140 | *) 141 | _last_positional="$1" 142 | _positionals+=("$_last_positional") 143 | _positionals_count=$((_positionals_count + 1)) 144 | ;; 145 | esac 146 | shift 147 | done 148 | } 149 | 150 | 151 | handle_passed_args_count() 152 | { 153 | test "${_positionals_count}" -le 1 || _PRINT_HELP=yes die "FATAL ERROR: There were spurious positional arguments --- we expect between 0 and 1, but got ${_positionals_count} (the last one was: '${_last_positional}')." 1 154 | } 155 | 156 | 157 | assign_positional_args() 158 | { 159 | local _positional_name _shift_for=$1 160 | _positional_names="_arg_qjs_version " 161 | 162 | shift "$_shift_for" 163 | for _positional_name in ${_positional_names} 164 | do 165 | test $# -gt 0 || break 166 | eval "$_positional_name=\${1}" || die "Error during argument parsing, possibly an Argbash bug." 1 167 | shift 168 | done 169 | } 170 | 171 | parse_commandline "$@" 172 | handle_passed_args_count 173 | assign_positional_args 1 "${_positionals[@]}" 174 | 175 | # OTHER STUFF GENERATED BY Argbash 176 | # Validation of values 177 | 178 | 179 | ### END OF CODE GENERATED BY Argbash (sortof) ### ]) 180 | # [ <-- needed because of Argbash 181 | 182 | 183 | # vvv PLACE YOUR CODE HERE vvv 184 | 185 | source "${script_dir}/../env/qjs" 186 | 187 | # ensure version exist 188 | qjs_commit="${qjs_commits[${_arg_qjs_version}]}" 189 | if [ -z ${qjs_commit} ] 190 | then 191 | _PRINT_HELP=yes die "QuickJS version '${_arg_qjs_version}' is not supported" 192 | fi 193 | 194 | # build QuickJS 195 | build_qjs() 196 | { 197 | [ ${_arg_verbose} == "on" ] && echo "Building 'QuickJS' version '${_arg_qjs_version}'..." 198 | 199 | # compiler binary 200 | _cc="${deps_dir}/musl_cc-${_arg_arch}/cc" 201 | 202 | # ensure cross compiler exists 203 | if ! [ -f ${_cc} ] 204 | then 205 | echo "Missing dependencies. Run 'fetch_deps.sh' script first" 1>&2 206 | return 1 207 | fi 208 | 209 | # ensure repository exists 210 | if ! [ -d ${repo_dir} ] 211 | then 212 | echo "Local repository does not exist. Run 'checkout_qjs.sh' script first" 1>&2 213 | return 1 214 | fi 215 | 216 | # If target architecture is not 'x86_64', ensure 'qjsc-x86_64' exists 217 | # since we will need its 'qjsc' binary to generate c files 218 | # It is supposed to be copied by 'checkout_qjs' script 219 | _qjsc_binary="${repo_dir}/qjsc" 220 | if [ ${_arg_arch} != "x86_64" ] 221 | then 222 | _qjsc_binary="${repo_dir}/qjsc-x86_64" 223 | if ! [ -f ${_qjsc_binary} ] 224 | then 225 | echo "File '${_qjsc_binary}' does not exist. Run 'prepare_qjs.sh' script first" 1>&2 226 | return 1 227 | fi 228 | fi 229 | 230 | # ensure expected commit is checked out 231 | cd ${repo_dir} && \ 232 | current_commit="$(git rev-parse HEAD)" 233 | if [ ${current_commit} != ${qjs_commit} ] 234 | then 235 | echo "Current commit (${current_commit}) does not match expected one (${qjs_commit}). Run 'checkout_qjs.sh' script first" 1>&2 236 | return 1 237 | fi 238 | 239 | # directory where QuickJS will be installed after being built 240 | _build_dir="${repo_dir}/BUILD-${_arg_qjs_version}-${_arg_arch}" 241 | # used to keep track of whether or not repo was patched 242 | _patched_marker="${repo_dir}/.patched-${_arg_qjs_version}" 243 | # used to keep track of whether or not QuickJS was already built 244 | _built_marker="${repo_dir}/.built-${_arg_qjs_version}-${_arg_arch}" 245 | # symlink in the repository, referencing the directory containing 'musl' build 246 | _musl_dir_symlink="${repo_dir}/musl-${_arg_arch}" 247 | 248 | # ensure patches were applied 249 | if ! [ -f ${_patched_marker} ] 250 | then 251 | echo "Local repository not patched. Run 'prepare_qjs.sh' script first" 1>&2 252 | return 1 253 | fi 254 | 255 | # ensure link to 'musl lib' exists 256 | if ! [ -d ${_musl_dir_symlink} ] 257 | then 258 | echo "'musl lib' symlink not found. Run 'prepare_qjs.sh' script first" 1>&2 259 | return 1 260 | fi 261 | 262 | # QuickJS was already built 263 | if [ -f ${_built_marker} ] && [ ${_arg_force} == "off" ] 264 | then 265 | [ ${_arg_verbose} == "on" ] && echo "No need to build 'QuickJS' version '${_arg_qjs_version}' for '${_arg_arch}'" 266 | else 267 | # build 268 | [ ${_arg_verbose} == "on" ] && echo "qjs_cc=${_cc} musl_arch=${_arg_arch} qjsc_binary=${_qjsc_binary} make" 269 | (rm -f ${_built_marker} && \ 270 | rm -f ${_commit_marker} && \ 271 | rm -fr ${_build_dir} && \ 272 | cd ${repo_dir} && \ 273 | make clean && \ 274 | qjs_cc=${_cc} musl_arch=${_arg_arch} qjsc_binary=${_qjsc_binary} make && \ 275 | DESTDIR=${_build_dir} make install) || return 1 276 | [ ${_arg_verbose} == "on" ] && echo "'QuickJS' version '${_arg_qjs_version}' successfully built for '${_arg_arch}'" 277 | fi 278 | 279 | # create build marker 280 | echo ${qjs_commit} >${_built_marker} || return 1 281 | 282 | return 0 283 | } 284 | 285 | _PRINT_HELP=no 286 | deps_dir=${_arg_deps_dir} 287 | repo_dir="${script_dir}/../../quickjs-repo" 288 | 289 | build_qjs || die "Could not build 'QuickJS' version '${_arg_qjs_version}' for '${_arg_arch}'" 290 | 291 | # ^^^ TERMINATE YOUR CODE BEFORE THE BOTTOM ARGBASH MARKER ^^^ 292 | 293 | # ] <-- needed because of Argbash 294 | -------------------------------------------------------------------------------- /builder/scripts/checkout_qjs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### 4 | # 5 | # Checkout a specific version of QuickJS from github 6 | # 7 | ### 8 | 9 | script_dir="$(cd "$(dirname "$(readlink -f "$0")")" && pwd)" || { echo "Couldn't determine the script's running directory, which probably matters, bailing out" >&2; exit 2; } 10 | source "${script_dir}/../env/qjs" 11 | 12 | # Created by argbash-init v2.10.0 13 | # ARG_OPTIONAL_BOOLEAN([force],[f],[clone repository even if it exists],[off]) 14 | # ARG_OPTIONAL_BOOLEAN([verbose],[v],[enable verbose mode],[off]) 15 | # ARG_POSITIONAL_SINGLE([qjs-version],[QuickJS version (ex: 2020-09-06)],[$default_qjs_version]) 16 | # ARG_HELP([Clone QuickJS repository & checkout a specific commit]) 17 | # ARGBASH_GO() 18 | # needed because of Argbash --> m4_ignore([ 19 | ### START OF CODE GENERATED BY Argbash v2.10.0 one line above ### 20 | # Argbash is a bash code generator used to get arguments parsing right. 21 | # Argbash is FREE SOFTWARE, see https://argbash.io for more info 22 | 23 | 24 | die() 25 | { 26 | local _ret="${2:-1}" 27 | test "${_PRINT_HELP:-no}" = yes && print_help >&2 28 | echo "$1" >&2 29 | exit "${_ret}" 30 | } 31 | 32 | 33 | begins_with_short_option() 34 | { 35 | local first_option all_short_options='fvh' 36 | first_option="${1:0:1}" 37 | test "$all_short_options" = "${all_short_options/$first_option/}" && return 1 || return 0 38 | } 39 | 40 | # THE DEFAULTS INITIALIZATION - POSITIONALS 41 | _positionals=() 42 | _arg_qjs_version="$default_qjs_version" 43 | # THE DEFAULTS INITIALIZATION - OPTIONALS 44 | _arg_force="off" 45 | _arg_verbose="off" 46 | 47 | 48 | print_help() 49 | { 50 | printf '%s\n' "Clone QuickJS repository & checkout a specific commit" 51 | printf 'Usage: %s [-f|--(no-)force] [-v|--(no-)verbose] [-h|--help] []\n' "$0" 52 | printf '\t%s\n' ": QuickJS version (ex: 2020-09-06) (default: '$default_qjs_version')" 53 | printf '\t%s\n' "-f, --force, --no-force: clone repository even if it exists (off by default)" 54 | printf '\t%s\n' "-v, --verbose, --no-verbose: enable verbose mode (off by default)" 55 | printf '\t%s\n' "-h, --help: Prints help" 56 | } 57 | 58 | 59 | parse_commandline() 60 | { 61 | _positionals_count=0 62 | while test $# -gt 0 63 | do 64 | _key="$1" 65 | case "$_key" in 66 | -f|--no-force|--force) 67 | _arg_force="on" 68 | test "${1:0:5}" = "--no-" && _arg_force="off" 69 | ;; 70 | -f*) 71 | _arg_force="on" 72 | _next="${_key##-f}" 73 | if test -n "$_next" -a "$_next" != "$_key" 74 | then 75 | { begins_with_short_option "$_next" && shift && set -- "-f" "-${_next}" "$@"; } || die "The short option '$_key' can't be decomposed to ${_key:0:2} and -${_key:2}, because ${_key:0:2} doesn't accept value and '-${_key:2:1}' doesn't correspond to a short option." 76 | fi 77 | ;; 78 | -v|--no-verbose|--verbose) 79 | _arg_verbose="on" 80 | test "${1:0:5}" = "--no-" && _arg_verbose="off" 81 | ;; 82 | -v*) 83 | _arg_verbose="on" 84 | _next="${_key##-v}" 85 | if test -n "$_next" -a "$_next" != "$_key" 86 | then 87 | { begins_with_short_option "$_next" && shift && set -- "-v" "-${_next}" "$@"; } || die "The short option '$_key' can't be decomposed to ${_key:0:2} and -${_key:2}, because ${_key:0:2} doesn't accept value and '-${_key:2:1}' doesn't correspond to a short option." 88 | fi 89 | ;; 90 | -h|--help) 91 | print_help 92 | exit 0 93 | ;; 94 | -h*) 95 | print_help 96 | exit 0 97 | ;; 98 | *) 99 | _last_positional="$1" 100 | _positionals+=("$_last_positional") 101 | _positionals_count=$((_positionals_count + 1)) 102 | ;; 103 | esac 104 | shift 105 | done 106 | } 107 | 108 | 109 | handle_passed_args_count() 110 | { 111 | test "${_positionals_count}" -le 1 || _PRINT_HELP=yes die "FATAL ERROR: There were spurious positional arguments --- we expect between 0 and 1, but got ${_positionals_count} (the last one was: '${_last_positional}')." 1 112 | } 113 | 114 | 115 | assign_positional_args() 116 | { 117 | local _positional_name _shift_for=$1 118 | _positional_names="_arg_qjs_version " 119 | 120 | shift "$_shift_for" 121 | for _positional_name in ${_positional_names} 122 | do 123 | test $# -gt 0 || break 124 | eval "$_positional_name=\${1}" || die "Error during argument parsing, possibly an Argbash bug." 1 125 | shift 126 | done 127 | } 128 | 129 | parse_commandline "$@" 130 | handle_passed_args_count 131 | assign_positional_args 1 "${_positionals[@]}" 132 | 133 | # OTHER STUFF GENERATED BY Argbash 134 | 135 | ### END OF CODE GENERATED BY Argbash (sortof) ### ]) 136 | # [ <-- needed because of Argbash 137 | 138 | 139 | # vvv PLACE YOUR CODE HERE vvv 140 | 141 | # ensure version exist 142 | qjs_commit="${qjs_commits[${_arg_qjs_version}]}" 143 | if [ -z ${qjs_commit} ] 144 | then 145 | _PRINT_HELP=yes die "QuickJS version '${_arg_qjs_version}' is not supported" 146 | fi 147 | 148 | # clone QuickJS repo 149 | clone_repo() 150 | { 151 | [ ${_arg_verbose} == "on" ] && echo "Cloning 'QuickJS' repository '${qjs_repository}'..." 152 | 153 | # no need to clone repository 154 | if [ -d ${repo_dir} ] && [ ${_arg_force} == "off" ] 155 | then 156 | [ ${_arg_verbose} == "on" ] && echo "No need to clone 'QuickJS' repository '${qjs_repository}'" 157 | else 158 | (rm -fr ${repo_dir} && \ 159 | cd ${script_dir}/.. && 160 | git clone ${qjs_repository} ${repo_dir}) || return 1 161 | [ ${_arg_verbose} == "on" ] && echo "Successfully cloned 'QuickJS' repository '$qjs_repository'" 162 | fi 163 | 164 | return 0 165 | } 166 | 167 | # Checkout a specific commit corresponding to the requested version 168 | checkout_commit() 169 | { 170 | [ ${_arg_verbose} == "on" ] && echo "Checking out 'QuickJS' commit '${qjs_commits[${_arg_qjs_version}]}'..." 171 | 172 | (cd ${repo_dir} && 173 | git checkout ${qjs_commits[${_arg_qjs_version}]}) || return 1 174 | 175 | [ ${_arg_verbose} == "on" ] && echo "Successfully checked out 'QuickJS' commit '${qjs_commits[${_arg_qjs_version}]}'" 176 | 177 | return 0 178 | } 179 | 180 | _PRINT_HELP=no 181 | src_dir="${script_dir}/../src" 182 | repo_dir="${script_dir}/../../quickjs-repo" 183 | 184 | clone_repo || die "Could not clone repository" 185 | checkout_commit || die "Could not checkout commit" 186 | 187 | # ^^^ TERMINATE YOUR CODE BEFORE THE BOTTOM ARGBASH MARKER ^^^ 188 | 189 | # ] <-- needed because of Argbash 190 | -------------------------------------------------------------------------------- /builder/scripts/export_qjs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### 4 | # 5 | # Export a portable package which can be used to generate static binaries 6 | # - strip binaries & static libraries 7 | # - compress binaries using upx 8 | # - add extra directories (optional) 9 | # - generate an archive compressed with xz 10 | # 11 | ### 12 | 13 | script_dir="$(cd "$(dirname "$(readlink -f "$0")")" && pwd)" || { echo "Couldn't determine the script's running directory, which probably matters, bailing out" >&2; exit 2; } 14 | source "${script_dir}/../env/qjs" 15 | 16 | # Created by argbash-init v2.10.0 17 | # ARG_OPTIONAL_SINGLE([deps-dir],[d],[directory containing dependencies],[$script_dir/../../deps]) 18 | # ARG_OPTIONAL_SINGLE([packages-dir],[p],[directory where package will be exported],[$script_dir/../../packages]) 19 | # ARG_OPTIONAL_BOOLEAN([verbose],[v],[enable verbose mode],[off]) 20 | # ARG_OPTIONAL_BOOLEAN([upx],[u],[compress binaries using upx],[on]) 21 | # ARG_OPTIONAL_SINGLE([arch],[a],[target architecture],[x86_64]) 22 | # ARG_OPTIONAL_BOOLEAN([ext-lib],[],[add QuickJS extension library],[off]) 23 | # ARG_OPTIONAL_SINGLE([ext-lib-version],[],[QuickJS extension library version],[$default_qjs_ext_lib_version]) 24 | # ARG_OPTIONAL_REPEATED([extra-dir],[e],[extra directory to add into package],[]) 25 | # ARG_POSITIONAL_SINGLE([qjs-version],[QuickJS version (ex: 2020-09-06)],[$default_qjs_version]) 26 | # ARG_TYPE_GROUP_SET([arch],[type string],[arch],[x86_64,i686,armv7l,aarch64]) 27 | # ARG_HELP([Export a tarball containing a static version of QuickJS and a static version of musl library]) 28 | # ARGBASH_GO() 29 | # needed because of Argbash --> m4_ignore([ 30 | ### START OF CODE GENERATED BY Argbash v2.10.0 one line above ### 31 | # Argbash is a bash code generator used to get arguments parsing right. 32 | # Argbash is FREE SOFTWARE, see https://argbash.io for more info 33 | 34 | 35 | die() 36 | { 37 | local _ret="${2:-1}" 38 | test "${_PRINT_HELP:-no}" = yes && print_help >&2 39 | echo "$1" >&2 40 | exit "${_ret}" 41 | } 42 | 43 | # validators 44 | 45 | arch() 46 | { 47 | local _allowed=("x86_64" "i686" "armv7l" "aarch64") _seeking="$1" 48 | for element in "${_allowed[@]}" 49 | do 50 | test "$element" = "$_seeking" && echo "$element" && return 0 51 | done 52 | die "Value '$_seeking' (of argument '$2') doesn't match the list of allowed values: 'x86_64', 'i686', 'armv7l' and 'aarch64'" 4 53 | } 54 | 55 | 56 | begins_with_short_option() 57 | { 58 | local first_option all_short_options='dpvuaeh' 59 | first_option="${1:0:1}" 60 | test "$all_short_options" = "${all_short_options/$first_option/}" && return 1 || return 0 61 | } 62 | 63 | # THE DEFAULTS INITIALIZATION - POSITIONALS 64 | _positionals=() 65 | _arg_qjs_version="$default_qjs_version" 66 | # THE DEFAULTS INITIALIZATION - OPTIONALS 67 | _arg_deps_dir="$script_dir/../../deps" 68 | _arg_packages_dir="$script_dir/../../packages" 69 | _arg_verbose="off" 70 | _arg_upx="on" 71 | _arg_arch="x86_64" 72 | _arg_ext_lib="off" 73 | _arg_ext_lib_version="$default_qjs_ext_lib_version" 74 | _arg_extra_dir=() 75 | 76 | 77 | print_help() 78 | { 79 | printf '%s\n' "Export a tarball containing a static version of QuickJS and a static version of musl library" 80 | printf 'Usage: %s [-d|--deps-dir ] [-p|--packages-dir ] [-v|--(no-)verbose] [-u|--(no-)upx] [-a|--arch ] [--(no-)ext-lib] [--ext-lib-version ] [-e|--extra-dir ] [-h|--help] []\n' "$0" 81 | printf '\t%s\n' ": QuickJS version (ex: 2020-09-06) (default: '$default_qjs_version')" 82 | printf '\t%s\n' "-d, --deps-dir: directory containing dependencies (default: '$script_dir/../../deps')" 83 | printf '\t%s\n' "-p, --packages-dir: directory where package will be exported (default: '$script_dir/../../packages')" 84 | printf '\t%s\n' "-v, --verbose, --no-verbose: enable verbose mode (off by default)" 85 | printf '\t%s\n' "-u, --upx, --no-upx: compress binaries using upx (on by default)" 86 | printf '\t%s\n' "-a, --arch: target architecture. Can be one of: 'x86_64', 'i686', 'armv7l' and 'aarch64' (default: 'x86_64')" 87 | printf '\t%s\n' "--ext-lib, --no-ext-lib: add QuickJS extension library (off by default)" 88 | printf '\t%s\n' "--ext-lib-version: QuickJS extension library version (default: '$default_qjs_ext_lib_version')" 89 | printf '\t%s\n' "-e, --extra-dir: extra directory to add into package (empty by default)" 90 | printf '\t%s\n' "-h, --help: Prints help" 91 | } 92 | 93 | 94 | parse_commandline() 95 | { 96 | _positionals_count=0 97 | while test $# -gt 0 98 | do 99 | _key="$1" 100 | case "$_key" in 101 | -d|--deps-dir) 102 | test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 103 | _arg_deps_dir="$2" 104 | shift 105 | ;; 106 | --deps-dir=*) 107 | _arg_deps_dir="${_key##--deps-dir=}" 108 | ;; 109 | -d*) 110 | _arg_deps_dir="${_key##-d}" 111 | ;; 112 | -p|--packages-dir) 113 | test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 114 | _arg_packages_dir="$2" 115 | shift 116 | ;; 117 | --packages-dir=*) 118 | _arg_packages_dir="${_key##--packages-dir=}" 119 | ;; 120 | -p*) 121 | _arg_packages_dir="${_key##-p}" 122 | ;; 123 | -v|--no-verbose|--verbose) 124 | _arg_verbose="on" 125 | test "${1:0:5}" = "--no-" && _arg_verbose="off" 126 | ;; 127 | -v*) 128 | _arg_verbose="on" 129 | _next="${_key##-v}" 130 | if test -n "$_next" -a "$_next" != "$_key" 131 | then 132 | { begins_with_short_option "$_next" && shift && set -- "-v" "-${_next}" "$@"; } || die "The short option '$_key' can't be decomposed to ${_key:0:2} and -${_key:2}, because ${_key:0:2} doesn't accept value and '-${_key:2:1}' doesn't correspond to a short option." 133 | fi 134 | ;; 135 | -u|--no-upx|--upx) 136 | _arg_upx="on" 137 | test "${1:0:5}" = "--no-" && _arg_upx="off" 138 | ;; 139 | -u*) 140 | _arg_upx="on" 141 | _next="${_key##-u}" 142 | if test -n "$_next" -a "$_next" != "$_key" 143 | then 144 | { begins_with_short_option "$_next" && shift && set -- "-u" "-${_next}" "$@"; } || die "The short option '$_key' can't be decomposed to ${_key:0:2} and -${_key:2}, because ${_key:0:2} doesn't accept value and '-${_key:2:1}' doesn't correspond to a short option." 145 | fi 146 | ;; 147 | -a|--arch) 148 | test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 149 | _arg_arch="$(arch "$2" "arch")" || exit 1 150 | shift 151 | ;; 152 | --arch=*) 153 | _arg_arch="$(arch "${_key##--arch=}" "arch")" || exit 1 154 | ;; 155 | -a*) 156 | _arg_arch="$(arch "${_key##-a}" "arch")" || exit 1 157 | ;; 158 | --no-ext-lib|--ext-lib) 159 | _arg_ext_lib="on" 160 | test "${1:0:5}" = "--no-" && _arg_ext_lib="off" 161 | ;; 162 | --ext-lib-version) 163 | test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 164 | _arg_ext_lib_version="$2" 165 | shift 166 | ;; 167 | --ext-lib-version=*) 168 | _arg_ext_lib_version="${_key##--ext-lib-version=}" 169 | ;; 170 | -e|--extra-dir) 171 | test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 172 | _arg_extra_dir+=("$2") 173 | shift 174 | ;; 175 | --extra-dir=*) 176 | _arg_extra_dir+=("${_key##--extra-dir=}") 177 | ;; 178 | -e*) 179 | _arg_extra_dir+=("${_key##-e}") 180 | ;; 181 | -h|--help) 182 | print_help 183 | exit 0 184 | ;; 185 | -h*) 186 | print_help 187 | exit 0 188 | ;; 189 | *) 190 | _last_positional="$1" 191 | _positionals+=("$_last_positional") 192 | _positionals_count=$((_positionals_count + 1)) 193 | ;; 194 | esac 195 | shift 196 | done 197 | } 198 | 199 | 200 | handle_passed_args_count() 201 | { 202 | test "${_positionals_count}" -le 1 || _PRINT_HELP=yes die "FATAL ERROR: There were spurious positional arguments --- we expect between 0 and 1, but got ${_positionals_count} (the last one was: '${_last_positional}')." 1 203 | } 204 | 205 | 206 | assign_positional_args() 207 | { 208 | local _positional_name _shift_for=$1 209 | _positional_names="_arg_qjs_version " 210 | 211 | shift "$_shift_for" 212 | for _positional_name in ${_positional_names} 213 | do 214 | test $# -gt 0 || break 215 | eval "$_positional_name=\${1}" || die "Error during argument parsing, possibly an Argbash bug." 1 216 | shift 217 | done 218 | } 219 | 220 | parse_commandline "$@" 221 | handle_passed_args_count 222 | assign_positional_args 1 "${_positionals[@]}" 223 | 224 | # OTHER STUFF GENERATED BY Argbash 225 | # Validation of values 226 | 227 | 228 | ### END OF CODE GENERATED BY Argbash (sortof) ### ]) 229 | # [ <-- needed because of Argbash 230 | 231 | 232 | # vvv PLACE YOUR CODE HERE vvv 233 | 234 | # ensure version exists 235 | qjs_commit="${qjs_commits[${_arg_qjs_version}]}" 236 | if [ -z ${qjs_commit} ] 237 | then 238 | _PRINT_HELP=yes die "QuickJS version '${_arg_qjs_version}' is not supported (commit unknown)" 239 | fi 240 | 241 | # ensure package name exists 242 | qjs_package="${qjs_packages[${_arg_qjs_version}]}" 243 | if [ -z ${qjs_package} ] 244 | then 245 | _PRINT_HELP=yes die "QuickJS version '${_arg_qjs_version}' is not supported (package unknown)" 246 | fi 247 | 248 | package_type=core 249 | if ! [ -z ${_arg_extra_dir} ] || [ ${_arg_ext_lib} == "on" ] 250 | then 251 | # we have been given directories to add to package 252 | package_type=ext 253 | fi 254 | 255 | # export QuickJS 256 | export_qjs() 257 | { 258 | [ ${_arg_verbose} == "on" ] && echo "Exporting 'QuickJS' version '${_arg_qjs_version}' (${package_type}) for '${_arg_arch}'..." 259 | 260 | if ! [ -d ${repo_dir} ] 261 | then 262 | echo "Local repository does not exist. Run 'checkout_qjs.sh' script first" 1>&2 263 | return 1 264 | fi 265 | 266 | # directory where QuickJS was installed afte being built 267 | _build_dir="${repo_dir}/BUILD-${_arg_qjs_version}-${_arg_arch}" 268 | # used to keep track of whether or not QuickJS was already built 269 | _built_marker="${repo_dir}/.built-${_arg_qjs_version}-${_arg_arch}" 270 | 271 | # ensure version was built 272 | if ! [ -f ${_built_marker} ] 273 | then 274 | echo "QuickJS version '${_arg_qjs_version}' was not built. Run 'build_qjs.sh' script first" 1>&2 275 | return 1 276 | fi 277 | 278 | # ensure version was built with expected commit 279 | _build_commit=$(head -1 ${_built_marker}) 280 | if [ ${_build_commit} != ${qjs_commit} ] 281 | then 282 | echo "QuickJS version '${_arg_qjs_version}' was built using commit (${_build_commit}) instead of expected one (${qjs_commit}). Run 'checkout_qjs.sh' script first" 1>&2 283 | return 1 284 | fi 285 | 286 | # name of the package which will be exported 287 | _package_name="quickjs.${package_type}.${qjs_package}.${_arg_arch}" 288 | # add qjs ext lib to the name if it has been added 289 | if [ ${_arg_ext_lib} == "on" ] 290 | then 291 | _package_name="quickjs.${package_type}.${qjs_package}.ext-lib-${_arg_ext_lib_version}.${_arg_arch}" 292 | fi 293 | # directory where package will be exported 294 | _package_dir="${packages_dir}/${_package_name}" 295 | # name of the exported tarball 296 | _package_tarball_filename="${_package_name}.tar.xz" 297 | # location of the final tarball 298 | _package_tarball="${packages_dir}/${_package_tarball_filename}" 299 | # symlink in the repository, referencing the directory containing 'musl' build 300 | _musl_dir_symlink="${repo_dir}/musl-${_arg_arch}" 301 | # list of files which need to be copied from the directory where QuickJS was installed 302 | _qjs_export_list="bin/qjs bin/qjsc lib/quickjs/libquickjs.a include/quickjs/quickjs-libc.h include/quickjs/quickjs.h" 303 | # list of QuickJS files which need to be stripped 304 | _qjs_strip_list="qjs qjsc libquickjs.a" 305 | # list of QuickJS files which need to be compressed using upx 306 | _qjs_upx_list="qjs qjsc" 307 | # list of qjs examples/tests files to copy 308 | _qjs_examples="examples/fib_module.js examples/hello.js examples/hello_module.js examples/pi_bigdecimal.js examples/pi_bigfloat.js examples/pi_bigint.js tests/microbench.js" 309 | # use 'strip' binary from cross compiler 310 | _strip="${deps_dir}/musl_cc-${_arg_arch}/strip" 311 | 312 | # create package directory 313 | (rm -fr ${_package_dir} && \ 314 | mkdir -p ${_package_dir}) || return 1 315 | 316 | # copy QuickJS files 317 | for _e in ${_qjs_export_list} 318 | do 319 | _file="${_build_dir}/${_e}" 320 | cp ${_file} ${_package_dir} || return 1 321 | done 322 | 323 | # strip QuickJS binaries & lib 324 | for _e in ${_qjs_strip_list} 325 | do 326 | _file="${_package_dir}/${_e}" 327 | if [ "$(basename ${_e} .a)" != "$(basename ${_e})" ] 328 | then 329 | # this is a static library 330 | ${_strip} -d ${_file} || return 1 331 | else 332 | # this is a binary 333 | ${_strip} ${_file} || return 1 334 | fi 335 | done 336 | 337 | if [ ${_arg_upx} == "on" ] 338 | then 339 | _upx_binary=$(which upx) 340 | if [ -z ${_upx_binary} ] 341 | then 342 | if [ ${_arg_verbose} == "on" ] 343 | then 344 | echo "Skipping 'QuickJS' binaries compression since 'upx' is not installed" 345 | fi 346 | else 347 | [ ${_arg_verbose} == "on" ] && echo "Compressing 'QuickJS' binaries..." 348 | for _e in ${_qjs_upx_list} 349 | do 350 | _file="${_package_dir}/${_e}" 351 | ${_upx_binary} ${_file} 352 | _result=$? 353 | if [ ${_result} -ne 0 ] 354 | then 355 | # don't do anything if binary is already compressed 356 | if [ ${_result} -ne 2 ] 357 | then 358 | echo "Could not compress 'QuickJS' binary '${_e}'" 1>&2 359 | return 1 360 | fi 361 | fi 362 | done 363 | fi 364 | fi 365 | 366 | # copy musl directory 367 | cp -RL ${_musl_dir_symlink} ${_package_dir} || return 1 368 | 369 | # copy examples & tests 370 | mkdir -p ${_package_dir}/examples || return 1 371 | for _filename in ${_qjs_examples} 372 | do 373 | _file="${repo_dir}/${_filename}" 374 | ! [ -f ${_file} ] && continue 375 | cp ${_file} ${_package_dir}/examples || return 1 376 | done 377 | 378 | # copy ext lib 379 | if [ ${_arg_ext_lib} == "on" ] 380 | then 381 | _ext_lib_tmp_dir=${_package_dir}/.ext_lib 382 | rm -fr ${_ext_lib_tmp_dir} && \ 383 | git clone ${qjs_ext_lib_repository} ${_ext_lib_tmp_dir} 384 | if [ $? -ne 0 ] 385 | then 386 | echo "Could not retrieve QuickJS extension library '${_arg_ext_lib_version}'" 1>&2 387 | return 1 388 | fi 389 | if [ ${_arg_ext_lib_version} != "master" ] 390 | then 391 | cd ${_ext_lib_tmp_dir} && git checkout tags/${_arg_ext_lib_version} 392 | if [ $? -ne 0 ] 393 | then 394 | echo "Could not retrieve QuickJS extension library '${_arg_ext_lib_version}'" 1>&2 395 | return 1 396 | fi 397 | fi 398 | # copy src files 399 | mkdir -p ${_package_dir}/ext && \ 400 | cp -R ${_ext_lib_tmp_dir}/src/* ${_package_dir}/ext && \ 401 | rm -fr ${_ext_lib_tmp_dir} 402 | fi 403 | 404 | # copy extra directories 405 | for _dir in ${_arg_extra_dir[@]} 406 | do 407 | # it might have been passed using format src:dest 408 | _src=$(echo ${_dir} | cut -d ':' -f1) 409 | _dest=$(echo ${_dir} | cut -d ':' -f2) 410 | # no destination was given 411 | if [ -z ${_dest} ] || [ ${_src} == ${_dest} ] 412 | then 413 | # copy directory 414 | cp -R ${_src} ${_package_dir} || return 1 415 | else 416 | _dirname=$(basename ${_dest}) 417 | # copy directory content 418 | mkdir -p ${_package_dir}/${_dirname} || return 1 419 | cp -R ${_src}/* ${_package_dir}/${_dirname} || return 1 420 | fi 421 | done 422 | 423 | # copy all scripts from 'custom' directory 424 | cp -R ${custom_dir}/qjs/scripts/* ${_package_dir} || return 1 425 | 426 | # copy ext lib examples 427 | if [ ${_arg_ext_lib} == "on" ] 428 | then 429 | cp -R ${custom_dir}/qjs/examples/ext-lib ${_package_dir}/examples || return 1 430 | fi 431 | 432 | # copy README 433 | cp -R ${custom_dir}/README.md ${_package_dir} || return 1 434 | 435 | # compress directory 436 | (cd ${packages_dir} && 437 | tar -C ${packages_dir} -cJf ${_package_tarball_filename} ${_package_name} && \ 438 | chmod 666 ${_package_tarball_filename} && \ 439 | rm -fr ${_package_dir}) || return 1 440 | 441 | [ ${_arg_verbose} == "on" ] && echo "'QuickJS' version '${_arg_qjs_version}' (${package_type}) successfully exported for '${_arg_arch}' to '${_package_tarball}'" 442 | 443 | return 0 444 | } 445 | 446 | # ensure all extra directories which should be copied exist 447 | for _dir in ${_arg_extra_dir[@]} 448 | do 449 | # it might have been passed using format src:dest 450 | _src=$(echo ${_dir} | cut -d ':' -f 1) 451 | ([ -z ${_src} ] || ! [ -d ${_src} ]) && die "Extra directory '${_src}' does not exist" 452 | done 453 | 454 | _PRINT_HELP=no 455 | repo_dir="${script_dir}/../../quickjs-repo" 456 | deps_dir=${_arg_deps_dir} 457 | packages_dir=${_arg_packages_dir} 458 | custom_dir="${script_dir}/../custom" 459 | 460 | mkdir -p ${packages_dir} 461 | 462 | export_qjs || die "Could not export 'QuickJS' version '${_arg_qjs_version}' for '${_arg_arch}'" 463 | 464 | # ^^^ TERMINATE YOUR CODE BEFORE THE BOTTOM ARGBASH MARKER ^^^ 465 | 466 | # ] <-- needed because of Argbash 467 | -------------------------------------------------------------------------------- /builder/scripts/fetch_deps.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### 4 | # 5 | # Fetch dependencies 6 | # - download musl sources 7 | # - download musl-based cross compiler (see https://github.com/ctn-malone/musl-cross-maker) 8 | # - create symlinks under the root directory ofr musl-cc compiler to maje compilation process easier 9 | # 10 | ### 11 | 12 | script_dir="$(cd "$(dirname "$(readlink -f "$0")")" && pwd)" || { echo "Couldn't determine the script's running directory, which probably matters, bailing out" >&2; exit 2; } 13 | 14 | # Created by argbash-init v2.10.0 15 | # ARG_OPTIONAL_SINGLE([deps-dir],[d],[directory where dependencies should be stored/built],[$script_dir/../../deps]) 16 | # ARG_OPTIONAL_SINGLE([arch],[a],[target architecture],[x86_64]) 17 | # ARG_OPTIONAL_BOOLEAN([force],[f],[force re-fetching dependencies],[off]) 18 | # ARG_OPTIONAL_BOOLEAN([verbose],[v],[enable verbose mode],[off]) 19 | # ARG_TYPE_GROUP_SET([arch],[type string],[arch],[x86_64,i686,armv7l,aarch64]) 20 | # ARG_HELP([Fetch dependencies needed to build a static version of QuickJS]) 21 | # ARGBASH_GO() 22 | # needed because of Argbash --> m4_ignore([ 23 | ### START OF CODE GENERATED BY Argbash v2.10.0 one line above ### 24 | # Argbash is a bash code generator used to get arguments parsing right. 25 | # Argbash is FREE SOFTWARE, see https://argbash.io for more info 26 | 27 | 28 | die() 29 | { 30 | local _ret="${2:-1}" 31 | test "${_PRINT_HELP:-no}" = yes && print_help >&2 32 | echo "$1" >&2 33 | exit "${_ret}" 34 | } 35 | 36 | # validators 37 | 38 | arch() 39 | { 40 | local _allowed=("x86_64" "i686" "armv7l" "aarch64") _seeking="$1" 41 | for element in "${_allowed[@]}" 42 | do 43 | test "$element" = "$_seeking" && echo "$element" && return 0 44 | done 45 | die "Value '$_seeking' (of argument '$2') doesn't match the list of allowed values: 'x86_64', 'i686', 'armv7l' and 'aarch64'" 4 46 | } 47 | 48 | 49 | begins_with_short_option() 50 | { 51 | local first_option all_short_options='dafvh' 52 | first_option="${1:0:1}" 53 | test "$all_short_options" = "${all_short_options/$first_option/}" && return 1 || return 0 54 | } 55 | 56 | # THE DEFAULTS INITIALIZATION - OPTIONALS 57 | _arg_deps_dir="$script_dir/../../deps" 58 | _arg_arch="x86_64" 59 | _arg_force="off" 60 | _arg_verbose="off" 61 | 62 | 63 | print_help() 64 | { 65 | printf '%s\n' "Fetch dependencies needed to build a static version of QuickJS" 66 | printf 'Usage: %s [-d|--deps-dir ] [-a|--arch ] [-f|--(no-)force] [-v|--(no-)verbose] [-h|--help]\n' "$0" 67 | printf '\t%s\n' "-d, --deps-dir: directory where dependencies should be stored/built (default: '$script_dir/../../deps')" 68 | printf '\t%s\n' "-a, --arch: target architecture. Can be one of: 'x86_64', 'i686', 'armv7l' and 'aarch64' (default: 'x86_64')" 69 | printf '\t%s\n' "-f, --force, --no-force: force re-fetching dependencies (off by default)" 70 | printf '\t%s\n' "-v, --verbose, --no-verbose: enable verbose mode (off by default)" 71 | printf '\t%s\n' "-h, --help: Prints help" 72 | } 73 | 74 | 75 | parse_commandline() 76 | { 77 | while test $# -gt 0 78 | do 79 | _key="$1" 80 | case "$_key" in 81 | -d|--deps-dir) 82 | test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 83 | _arg_deps_dir="$2" 84 | shift 85 | ;; 86 | --deps-dir=*) 87 | _arg_deps_dir="${_key##--deps-dir=}" 88 | ;; 89 | -d*) 90 | _arg_deps_dir="${_key##-d}" 91 | ;; 92 | -a|--arch) 93 | test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 94 | _arg_arch="$(arch "$2" "arch")" || exit 1 95 | shift 96 | ;; 97 | --arch=*) 98 | _arg_arch="$(arch "${_key##--arch=}" "arch")" || exit 1 99 | ;; 100 | -a*) 101 | _arg_arch="$(arch "${_key##-a}" "arch")" || exit 1 102 | ;; 103 | -f|--no-force|--force) 104 | _arg_force="on" 105 | test "${1:0:5}" = "--no-" && _arg_force="off" 106 | ;; 107 | -f*) 108 | _arg_force="on" 109 | _next="${_key##-f}" 110 | if test -n "$_next" -a "$_next" != "$_key" 111 | then 112 | { begins_with_short_option "$_next" && shift && set -- "-f" "-${_next}" "$@"; } || die "The short option '$_key' can't be decomposed to ${_key:0:2} and -${_key:2}, because ${_key:0:2} doesn't accept value and '-${_key:2:1}' doesn't correspond to a short option." 113 | fi 114 | ;; 115 | -v|--no-verbose|--verbose) 116 | _arg_verbose="on" 117 | test "${1:0:5}" = "--no-" && _arg_verbose="off" 118 | ;; 119 | -v*) 120 | _arg_verbose="on" 121 | _next="${_key##-v}" 122 | if test -n "$_next" -a "$_next" != "$_key" 123 | then 124 | { begins_with_short_option "$_next" && shift && set -- "-v" "-${_next}" "$@"; } || die "The short option '$_key' can't be decomposed to ${_key:0:2} and -${_key:2}, because ${_key:0:2} doesn't accept value and '-${_key:2:1}' doesn't correspond to a short option." 125 | fi 126 | ;; 127 | -h|--help) 128 | print_help 129 | exit 0 130 | ;; 131 | -h*) 132 | print_help 133 | exit 0 134 | ;; 135 | *) 136 | _PRINT_HELP=yes die "FATAL ERROR: Got an unexpected argument '$1'" 1 137 | ;; 138 | esac 139 | shift 140 | done 141 | } 142 | 143 | parse_commandline "$@" 144 | 145 | # OTHER STUFF GENERATED BY Argbash 146 | # Validation of values 147 | 148 | 149 | ### END OF CODE GENERATED BY Argbash (sortof) ### ]) 150 | # [ <-- needed because of Argbash 151 | 152 | 153 | # vvv PLACE YOUR CODE HERE vvv 154 | source "${script_dir}/../env/deps" 155 | 156 | # Fetch 'musl-cc' tarball, decompress & create symlink under ${deps_dir} 157 | fetch_musl_cc() 158 | { 159 | [ ${_arg_verbose} == "on" ] && echo "Downloading 'musl-cc' for '${_arg_arch}'..." 160 | 161 | case ${_arg_arch} in 162 | x86_64) 163 | declare -n _cfg="cfg_musl_cc_x86_64" 164 | ;; 165 | i686) 166 | declare -n _cfg="cfg_musl_cc_i686" 167 | ;; 168 | armv7l) 169 | declare -n _cfg="cfg_musl_cc_armv7l" 170 | ;; 171 | aarch64) 172 | declare -n _cfg="cfg_musl_cc_aarch64" 173 | ;; 174 | esac 175 | 176 | # directory which will contain 'musl-cc' files after decompression 177 | _archive_dir="${archives_dir}/${_cfg["archive_dir"]}" 178 | # location of the archive file after download 179 | _archive=${archives_dir}/$(basename "${_cfg["archive_url"]}") 180 | # symlink under 'deps' directory, referencing the directory containing 'musl-cc' files 181 | _archive_dir_symlink=${deps_dir}/${_cfg["archive_dir_symlink"]} 182 | # compiler's target (ex: x86_64-linux-musl) 183 | _machine=$(echo "${_cfg["archive_dir"]}" | sed 's/-cross.*//') 184 | # symlinks created at the root of the directory containing 'musl_cc' files 185 | _cc_symlink=${_archive_dir}/cc 186 | _strip_symlink=${_archive_dir}/strip 187 | _libatomic_symlink=${_archive_dir}/libatomic.a 188 | _libssp_nonshared_symlink=${_archive_dir}/libssp_nonshared.a 189 | 190 | # dependency already fetched & decompressed 191 | if [ -d ${_archive_dir} ] && [ ${_arg_force} == "off" ] 192 | then 193 | [ ${_arg_verbose} == "on" ] && echo "No need to download 'musl-cc' for '${_arg_arch}'" 194 | else 195 | # fetch tarball & decompress 196 | (rm -fr ${_archive_dir} && \ 197 | wget -O ${_archive} ${_cfg["archive_url"]} && \ 198 | tar -C ${archives_dir} -xzf ${_archive}) || return 1 199 | [ ${_arg_verbose} == "on" ] && echo "Successfully downloaded 'musl-cc' for '${_arg_arch}'" 200 | fi 201 | 202 | # create symlink to archive directory 203 | (rm -f ${_archive_dir_symlink} && 204 | ln -s "$(basename ${archives_dir})/${_cfg["archive_dir"]}" ${_archive_dir_symlink}) || return 1 205 | 206 | # create symlink to 'cc' binary 207 | (rm -f ${_cc_symlink} && 208 | ln -s "bin/${_machine}-cc" ${_cc_symlink}) || return 1 209 | 210 | # create symlink to 'strip' binary 211 | (rm -f ${_strip_symlink} && 212 | ln -s "bin/${_machine}-strip" ${_strip_symlink}) || return 1 213 | 214 | # create symlink to 'libatomic' static library 215 | (rm -f ${_libatomic_symlink} && 216 | ln -s "${_machine}/lib/libatomic.a" ${_libatomic_symlink}) || return 1 217 | 218 | # create symlink to 'libssp_nonshared' static library 219 | (rm -f ${_libssp_nonshared_symlink} && 220 | ln -s "${_machine}/lib/libssp_nonshared.a" ${_libssp_nonshared_symlink}) || return 1 221 | 222 | return 0 223 | } 224 | 225 | # Fetch 'musl lib' tarball, decompress & create symlink under ${deps_dir} 226 | fetch_musl_lib() 227 | { 228 | [ ${_arg_verbose} == "on" ] && echo "Downloading 'musl lib'..." 229 | 230 | declare -n _cfg="cfg_musl_lib" 231 | 232 | # directory which will contain 'musl' sources after decompression 233 | _archive_dir="${archives_dir}/${_cfg["archive_dir"]}" 234 | # location of the archive file after download 235 | _archive=${archives_dir}/$(basename "${_cfg["archive_url"]}") 236 | # symlink under 'deps' directory, referencing the directory containing 'musl-cc' sources 237 | _archive_dir_symlink=${deps_dir}/${_cfg["archive_dir_symlink"]} 238 | 239 | # dependency already fetched & decompressed 240 | if [ -d ${_archive_dir} ] && [ ${_arg_force} == "off" ] 241 | then 242 | [ ${_arg_verbose} == "on" ] && echo "No need to download 'musl lib'" 243 | else 244 | # fetch tarball & decompress 245 | (rm -fr ${_archive_dir} && \ 246 | wget -O ${_archive} ${_cfg["archive_url"]} && \ 247 | tar -C ${archives_dir} -xzf ${_archive}) || return 1 248 | [ ${_arg_verbose} == "on" ] && echo "Successfully downloaded 'musl lib'" 249 | fi 250 | 251 | # create symlink to archive directory 252 | (rm -f ${_archive_dir_symlink} && 253 | ln -s "$(basename ${archives_dir})/${_cfg["archive_dir"]}" ${_archive_dir_symlink}) || return 1 254 | 255 | return 0 256 | } 257 | 258 | # fetch all dependencies 259 | fetch_deps() 260 | { 261 | [ ${_arg_verbose} == "on" ] && echo "Fetching dependencies for '${_arg_arch}'..." 262 | 263 | fetch_musl_lib || return 1 264 | fetch_musl_cc || return 1 265 | 266 | [ ${_arg_verbose} == "on" ] && echo "Dependencies for '${_arg_arch}' successfully fetched" 267 | 268 | return 0 269 | } 270 | 271 | _PRINT_HELP=no 272 | deps_dir=${_arg_deps_dir} 273 | # directory where archives will be downloaded 274 | archives_dir=${deps_dir}/archives 275 | 276 | mkdir -p ${archives_dir} 277 | 278 | fetch_deps || die "Could not fetch dependencies" 279 | 280 | # ^^^ TERMINATE YOUR CODE BEFORE THE BOTTOM ARGBASH MARKER ^^^ 281 | 282 | # ] <-- needed because of Argbash 283 | -------------------------------------------------------------------------------- /builder/scripts/prepare_qjs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### 4 | # 5 | # Prepare QuickJS repository 6 | # - apply some patches (Makefile, qjsc.c ...) 7 | # - create a symlink to the directory containing the musl lib build 8 | # - copy the qjsc_x86_64 binary which will be needed to generate .c file during cross-compilation 9 | # 10 | ### 11 | 12 | script_dir="$(cd "$(dirname "$(readlink -f "$0")")" && pwd)" || { echo "Couldn't determine the script's running directory, which probably matters, bailing out" >&2; exit 2; } 13 | source "${script_dir}/../env/qjs" 14 | 15 | # Created by argbash-init v2.10.0 16 | # ARG_OPTIONAL_SINGLE([deps-dir],[d],[directory containing dependencies],[$script_dir/../../deps]) 17 | # ARG_OPTIONAL_SINGLE([arch],[a],[target architecture],[x86_64]) 18 | # ARG_OPTIONAL_BOOLEAN([verbose],[v],[enable verbose mode],[off]) 19 | # ARG_POSITIONAL_SINGLE([qjs-version],[QuickJS version (ex: 2020-09-06)],[$default_qjs_version]) 20 | # ARG_TYPE_GROUP_SET([arch],[type string],[arch],[x86_64,i686,armv7l,aarch64]) 21 | # ARG_HELP([Patch QuickJS sources & create symlink to static musl lib]) 22 | # ARGBASH_GO() 23 | # needed because of Argbash --> m4_ignore([ 24 | ### START OF CODE GENERATED BY Argbash v2.10.0 one line above ### 25 | # Argbash is a bash code generator used to get arguments parsing right. 26 | # Argbash is FREE SOFTWARE, see https://argbash.io for more info 27 | 28 | 29 | die() 30 | { 31 | local _ret="${2:-1}" 32 | test "${_PRINT_HELP:-no}" = yes && print_help >&2 33 | echo "$1" >&2 34 | exit "${_ret}" 35 | } 36 | 37 | # validators 38 | 39 | arch() 40 | { 41 | local _allowed=("x86_64" "i686" "armv7l" "aarch64") _seeking="$1" 42 | for element in "${_allowed[@]}" 43 | do 44 | test "$element" = "$_seeking" && echo "$element" && return 0 45 | done 46 | die "Value '$_seeking' (of argument '$2') doesn't match the list of allowed values: 'x86_64', 'i686', 'armv7l' and 'aarch64'" 4 47 | } 48 | 49 | 50 | begins_with_short_option() 51 | { 52 | local first_option all_short_options='davh' 53 | first_option="${1:0:1}" 54 | test "$all_short_options" = "${all_short_options/$first_option/}" && return 1 || return 0 55 | } 56 | 57 | # THE DEFAULTS INITIALIZATION - POSITIONALS 58 | _positionals=() 59 | _arg_qjs_version="$default_qjs_version" 60 | # THE DEFAULTS INITIALIZATION - OPTIONALS 61 | _arg_deps_dir="$script_dir/../../deps" 62 | _arg_arch="x86_64" 63 | _arg_verbose="off" 64 | 65 | 66 | print_help() 67 | { 68 | printf '%s\n' "Patch QuickJS sources & create symlink to static musl lib" 69 | printf 'Usage: %s [-d|--deps-dir ] [-a|--arch ] [-v|--(no-)verbose] [-h|--help] []\n' "$0" 70 | printf '\t%s\n' ": QuickJS version (ex: 2020-09-06) (default: '$default_qjs_version')" 71 | printf '\t%s\n' "-d, --deps-dir: directory containing dependencies (default: '$script_dir/../../deps')" 72 | printf '\t%s\n' "-a, --arch: target architecture. Can be one of: 'x86_64', 'i686', 'armv7l' and 'aarch64' (default: 'x86_64')" 73 | printf '\t%s\n' "-v, --verbose, --no-verbose: enable verbose mode (off by default)" 74 | printf '\t%s\n' "-h, --help: Prints help" 75 | } 76 | 77 | 78 | parse_commandline() 79 | { 80 | _positionals_count=0 81 | while test $# -gt 0 82 | do 83 | _key="$1" 84 | case "$_key" in 85 | -d|--deps-dir) 86 | test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 87 | _arg_deps_dir="$2" 88 | shift 89 | ;; 90 | --deps-dir=*) 91 | _arg_deps_dir="${_key##--deps-dir=}" 92 | ;; 93 | -d*) 94 | _arg_deps_dir="${_key##-d}" 95 | ;; 96 | -a|--arch) 97 | test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 98 | _arg_arch="$(arch "$2" "arch")" || exit 1 99 | shift 100 | ;; 101 | --arch=*) 102 | _arg_arch="$(arch "${_key##--arch=}" "arch")" || exit 1 103 | ;; 104 | -a*) 105 | _arg_arch="$(arch "${_key##-a}" "arch")" || exit 1 106 | ;; 107 | -v|--no-verbose|--verbose) 108 | _arg_verbose="on" 109 | test "${1:0:5}" = "--no-" && _arg_verbose="off" 110 | ;; 111 | -v*) 112 | _arg_verbose="on" 113 | _next="${_key##-v}" 114 | if test -n "$_next" -a "$_next" != "$_key" 115 | then 116 | { begins_with_short_option "$_next" && shift && set -- "-v" "-${_next}" "$@"; } || die "The short option '$_key' can't be decomposed to ${_key:0:2} and -${_key:2}, because ${_key:0:2} doesn't accept value and '-${_key:2:1}' doesn't correspond to a short option." 117 | fi 118 | ;; 119 | -h|--help) 120 | print_help 121 | exit 0 122 | ;; 123 | -h*) 124 | print_help 125 | exit 0 126 | ;; 127 | *) 128 | _last_positional="$1" 129 | _positionals+=("$_last_positional") 130 | _positionals_count=$((_positionals_count + 1)) 131 | ;; 132 | esac 133 | shift 134 | done 135 | } 136 | 137 | 138 | handle_passed_args_count() 139 | { 140 | test "${_positionals_count}" -le 1 || _PRINT_HELP=yes die "FATAL ERROR: There were spurious positional arguments --- we expect between 0 and 1, but got ${_positionals_count} (the last one was: '${_last_positional}')." 1 141 | } 142 | 143 | 144 | assign_positional_args() 145 | { 146 | local _positional_name _shift_for=$1 147 | _positional_names="_arg_qjs_version " 148 | 149 | shift "$_shift_for" 150 | for _positional_name in ${_positional_names} 151 | do 152 | test $# -gt 0 || break 153 | eval "$_positional_name=\${1}" || die "Error during argument parsing, possibly an Argbash bug." 1 154 | shift 155 | done 156 | } 157 | 158 | parse_commandline "$@" 159 | handle_passed_args_count 160 | assign_positional_args 1 "${_positionals[@]}" 161 | 162 | # OTHER STUFF GENERATED BY Argbash 163 | # Validation of values 164 | 165 | 166 | ### END OF CODE GENERATED BY Argbash (sortof) ### ]) 167 | # [ <-- needed because of Argbash 168 | 169 | 170 | # vvv PLACE YOUR CODE HERE vvv 171 | 172 | # ensure version exist 173 | qjs_commit="${qjs_commits[${_arg_qjs_version}]}" 174 | if [ -z ${qjs_commit} ] 175 | then 176 | _PRINT_HELP=yes die "QuickJS version '${_arg_qjs_version}' is not supported" 177 | fi 178 | 179 | # patch QuickJS source files 180 | patch_qjs() 181 | { 182 | [ ${_arg_verbose} == "on" ] && echo "Patching 'QuickJS' sources..." 183 | 184 | # ensure repository exists 185 | if ! [ -d ${repo_dir} ] 186 | then 187 | echo "Local repository does not exist. Run 'checkout_qjs.sh' script first" 1>&2 188 | return 1 189 | fi 190 | 191 | # ensure expected commit is checked out 192 | cd ${repo_dir} && \ 193 | current_commit="$(git rev-parse HEAD)" 194 | if [ ${current_commit} != ${qjs_commit} ] 195 | then 196 | echo "Current commit (${current_commit}) does not match expected one (${qjs_commit}). Run 'checkout_qjs.sh' script first" 1>&2 197 | return 1 198 | fi 199 | 200 | # change VERSION file 201 | qjs_package="${qjs_packages[${_arg_qjs_version}]}" 202 | if [ -z ${qjs_package} ] 203 | then 204 | _PRINT_HELP=yes die "QuickJS version '${_arg_qjs_version}' is not supported (package unknown)" 205 | fi 206 | echo "${qjs_package}\ \(https://github.com/ctn-malone/quickjs-cross-compiler\)" >${repo_dir}/VERSION 207 | 208 | _patch_dir="${custom_dir}/qjs/patches/${_arg_qjs_version}" 209 | _need_patch=0 210 | # used to keep track of whether or not repo was patched 211 | _patched_marker="${repo_dir}/.patched-${_arg_qjs_version}" 212 | 213 | # patches have already been applied 214 | if ! [ -f ${_patched_marker} ] 215 | then 216 | cd ${repo_dir} 217 | 218 | for file in $(ls $_patch_dir/*.patch) 219 | do 220 | # check if patch has already been applied 221 | patch -Rp1 -s -f --dry-run <$file >/dev/null 2>&1 222 | if [ $? -ne 0 ] 223 | then 224 | _need_patch=1 225 | patch -Np1 <$file || return 1 226 | fi 227 | done 228 | # create marker 229 | touch ${_patched_marker} 230 | fi 231 | 232 | if [ ${_need_patch} -eq 0 ] 233 | then 234 | [ ${_arg_verbose} == "on" ] && echo "'QuickJS' sources already patched" 235 | else 236 | [ ${_arg_verbose} == "on" ] && echo "Successfully patched 'QuickJS' sources" 237 | fi 238 | 239 | return 0 240 | } 241 | 242 | # create symlink to static musl lib 243 | create_musl_symlink() 244 | { 245 | [ ${_arg_verbose} == "on" ] && echo "Creating symlink to 'musl lib' for '${_arg_arch}'..." 246 | 247 | # used to keep track of whether or not musl lib was built 248 | _musl_built_marker="${deps_dir}/musl/.built-${_arg_arch}" 249 | # directory where musl was build 250 | _musl_dir="${deps_dir}/musl/BUILD-${_arg_arch}" 251 | # symlink in the repository, referencing the directory containing 'musl' build 252 | _musl_dir_symlink="${repo_dir}/musl-${_arg_arch}" 253 | 254 | # ensure musl was built 255 | if ! [ -f ${_musl_built_marker} ] 256 | then 257 | echo "'musl lib' was not built for '${_arg_arch}'. Run 'build_deps.sh' script first" 1>&2 258 | return 1 259 | fi 260 | 261 | (rm -f ${_musl_dir_symlink} && \ 262 | ln -s ${_musl_dir} ${_musl_dir_symlink}) || return 1 263 | 264 | [ ${_arg_verbose} == "on" ] && echo "Successfully created symlink to 'musl lib' for '${_arg_arch}'" 265 | 266 | return 0 267 | } 268 | 269 | _PRINT_HELP=no 270 | deps_dir=${_arg_deps_dir} 271 | repo_dir="${script_dir}/../../quickjs-repo" 272 | # directory containing custom files such as patches to apply 273 | custom_dir="${script_dir}/../custom" 274 | 275 | patch_qjs || die "Could not patch 'QuickJS'" 276 | # 'x86_64' version of the binary is needed to generate c files when doing cross-compilation 277 | cp ${custom_dir}/qjs/qjsc-x86_64 ${repo_dir} || die "Could not copy 'qjsc-x86_64' to repository" 278 | # copy extra source files 279 | cp -R ${custom_dir}/qjs/files/* ${repo_dir} || die "Could not copy extra source files to repository" 280 | create_musl_symlink || die "Could not create symlink to 'musl lib'" 281 | 282 | # ^^^ TERMINATE YOUR CODE BEFORE THE BOTTOM ARGBASH MARKER ^^^ 283 | 284 | # ] <-- needed because of Argbash 285 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.12.0 2 | ARG arch=x86_64 3 | WORKDIR /usr/local/src/quickjs-cross-compiler/builder 4 | COPY builder /tmp/builder 5 | RUN /tmp/builder/scripts/bootstrap-alpine.sh && \ 6 | /tmp/builder/scripts/fetch_deps.sh -va $arch -d /usr/local/src/quickjs-cross-compiler/deps && \ 7 | /tmp/builder/scripts/build_deps.sh -va $arch -d /usr/local/src/quickjs-cross-compiler/deps 8 | -------------------------------------------------------------------------------- /docker/build_and_export_qjs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### 4 | # 5 | # Build a static version of QuickJS (interpreter & compiler) 6 | # Export a portable package which can be used to generate static binaries 7 | # 8 | ### 9 | 10 | script_dir="$(cd "$(dirname "$(readlink -f "$0")")" && pwd)" || { echo "Couldn't determine the script's running directory, which probably matters, bailing out" >&2; exit 2; } 11 | source "${script_dir}/../builder/env/qjs" 12 | 13 | # Created by argbash-init v2.10.0 14 | # ARG_OPTIONAL_SINGLE([packages-dir],[p],[directory where package will be exported],[$script_dir/../packages]) 15 | # ARG_OPTIONAL_SINGLE([arch],[a],[target architecture],[x86_64]) 16 | # ARG_OPTIONAL_BOOLEAN([ext-lib],[],[add QuickJS extension library],[off]) 17 | # ARG_OPTIONAL_SINGLE([ext-lib-version],[],[QuickJS extension library version],[$default_qjs_ext_lib_version]) 18 | # ARG_OPTIONAL_REPEATED([extra-dir],[e],[extra directory to add into package],[]) 19 | # ARG_OPTIONAL_BOOLEAN([force-build-image],[],[force rebuilding docker image],[off]) 20 | # ARG_OPTIONAL_BOOLEAN([verbose],[v],[enable verbose mode],[off]) 21 | # ARG_OPTIONAL_BOOLEAN([upx],[u],[compress binaries using upx],[on]) 22 | # ARG_POSITIONAL_SINGLE([qjs-version],[QuickJS version (ex: 2020-09-06)],[$default_qjs_version]) 23 | # ARG_TYPE_GROUP_SET([arch],[type string],[arch],[x86_64,i686,armv7l,aarch64]) 24 | # ARG_HELP([Build a static version of QuickJS (interpreter & compiler)]) 25 | # ARGBASH_GO() 26 | # needed because of Argbash --> m4_ignore([ 27 | ### START OF CODE GENERATED BY Argbash v2.10.0 one line above ### 28 | # Argbash is a bash code generator used to get arguments parsing right. 29 | # Argbash is FREE SOFTWARE, see https://argbash.io for more info 30 | 31 | 32 | die() 33 | { 34 | local _ret="${2:-1}" 35 | test "${_PRINT_HELP:-no}" = yes && print_help >&2 36 | echo "$1" >&2 37 | exit "${_ret}" 38 | } 39 | 40 | # validators 41 | 42 | arch() 43 | { 44 | local _allowed=("x86_64" "i686" "armv7l" "aarch64") _seeking="$1" 45 | for element in "${_allowed[@]}" 46 | do 47 | test "$element" = "$_seeking" && echo "$element" && return 0 48 | done 49 | die "Value '$_seeking' (of argument '$2') doesn't match the list of allowed values: 'x86_64', 'i686', 'armv7l' and 'aarch64'" 4 50 | } 51 | 52 | 53 | begins_with_short_option() 54 | { 55 | local first_option all_short_options='paevuh' 56 | first_option="${1:0:1}" 57 | test "$all_short_options" = "${all_short_options/$first_option/}" && return 1 || return 0 58 | } 59 | 60 | # THE DEFAULTS INITIALIZATION - POSITIONALS 61 | _positionals=() 62 | _arg_qjs_version="$default_qjs_version" 63 | # THE DEFAULTS INITIALIZATION - OPTIONALS 64 | _arg_packages_dir="$script_dir/../packages" 65 | _arg_arch="x86_64" 66 | _arg_ext_lib="off" 67 | _arg_ext_lib_version="$default_qjs_ext_lib_version" 68 | _arg_extra_dir=() 69 | _arg_force_build_image="off" 70 | _arg_verbose="off" 71 | _arg_upx="on" 72 | 73 | 74 | print_help() 75 | { 76 | printf '%s\n' "Build a static version of QuickJS (interpreter & compiler)" 77 | printf 'Usage: %s [-p|--packages-dir ] [-a|--arch ] [--(no-)ext-lib] [--ext-lib-version ] [-e|--extra-dir ] [--(no-)force-build-image] [-v|--(no-)verbose] [-u|--(no-)upx] [-h|--help] []\n' "$0" 78 | printf '\t%s\n' ": QuickJS version (ex: 2020-09-06) (default: '$default_qjs_version')" 79 | printf '\t%s\n' "-p, --packages-dir: directory where package will be exported (default: '$script_dir/../packages')" 80 | printf '\t%s\n' "-a, --arch: target architecture. Can be one of: 'x86_64', 'i686', 'armv7l' and 'aarch64' (default: 'x86_64')" 81 | printf '\t%s\n' "--ext-lib, --no-ext-lib: add QuickJS extension library (off by default)" 82 | printf '\t%s\n' "--ext-lib-version: QuickJS extension library version (default: '$default_qjs_ext_lib_version')" 83 | printf '\t%s\n' "-e, --extra-dir: extra directory to add into package (empty by default)" 84 | printf '\t%s\n' "--force-build-image, --no-force-build-image: force rebuilding docker image (off by default)" 85 | printf '\t%s\n' "-v, --verbose, --no-verbose: enable verbose mode (off by default)" 86 | printf '\t%s\n' "-u, --upx, --no-upx: compress binaries using upx (on by default)" 87 | printf '\t%s\n' "-h, --help: Prints help" 88 | } 89 | 90 | 91 | parse_commandline() 92 | { 93 | _positionals_count=0 94 | while test $# -gt 0 95 | do 96 | _key="$1" 97 | case "$_key" in 98 | -p|--packages-dir) 99 | test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 100 | _arg_packages_dir="$2" 101 | shift 102 | ;; 103 | --packages-dir=*) 104 | _arg_packages_dir="${_key##--packages-dir=}" 105 | ;; 106 | -p*) 107 | _arg_packages_dir="${_key##-p}" 108 | ;; 109 | -a|--arch) 110 | test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 111 | _arg_arch="$(arch "$2" "arch")" || exit 1 112 | shift 113 | ;; 114 | --arch=*) 115 | _arg_arch="$(arch "${_key##--arch=}" "arch")" || exit 1 116 | ;; 117 | -a*) 118 | _arg_arch="$(arch "${_key##-a}" "arch")" || exit 1 119 | ;; 120 | --no-ext-lib|--ext-lib) 121 | _arg_ext_lib="on" 122 | test "${1:0:5}" = "--no-" && _arg_ext_lib="off" 123 | ;; 124 | --ext-lib-version) 125 | test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 126 | _arg_ext_lib_version="$2" 127 | shift 128 | ;; 129 | --ext-lib-version=*) 130 | _arg_ext_lib_version="${_key##--ext-lib-version=}" 131 | ;; 132 | -e|--extra-dir) 133 | test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 134 | _arg_extra_dir+=("$2") 135 | shift 136 | ;; 137 | --extra-dir=*) 138 | _arg_extra_dir+=("${_key##--extra-dir=}") 139 | ;; 140 | -e*) 141 | _arg_extra_dir+=("${_key##-e}") 142 | ;; 143 | --no-force-build-image|--force-build-image) 144 | _arg_force_build_image="on" 145 | test "${1:0:5}" = "--no-" && _arg_force_build_image="off" 146 | ;; 147 | -v|--no-verbose|--verbose) 148 | _arg_verbose="on" 149 | test "${1:0:5}" = "--no-" && _arg_verbose="off" 150 | ;; 151 | -v*) 152 | _arg_verbose="on" 153 | _next="${_key##-v}" 154 | if test -n "$_next" -a "$_next" != "$_key" 155 | then 156 | { begins_with_short_option "$_next" && shift && set -- "-v" "-${_next}" "$@"; } || die "The short option '$_key' can't be decomposed to ${_key:0:2} and -${_key:2}, because ${_key:0:2} doesn't accept value and '-${_key:2:1}' doesn't correspond to a short option." 157 | fi 158 | ;; 159 | -u|--no-upx|--upx) 160 | _arg_upx="on" 161 | test "${1:0:5}" = "--no-" && _arg_upx="off" 162 | ;; 163 | -u*) 164 | _arg_upx="on" 165 | _next="${_key##-u}" 166 | if test -n "$_next" -a "$_next" != "$_key" 167 | then 168 | { begins_with_short_option "$_next" && shift && set -- "-u" "-${_next}" "$@"; } || die "The short option '$_key' can't be decomposed to ${_key:0:2} and -${_key:2}, because ${_key:0:2} doesn't accept value and '-${_key:2:1}' doesn't correspond to a short option." 169 | fi 170 | ;; 171 | -h|--help) 172 | print_help 173 | exit 0 174 | ;; 175 | -h*) 176 | print_help 177 | exit 0 178 | ;; 179 | *) 180 | _last_positional="$1" 181 | _positionals+=("$_last_positional") 182 | _positionals_count=$((_positionals_count + 1)) 183 | ;; 184 | esac 185 | shift 186 | done 187 | } 188 | 189 | 190 | handle_passed_args_count() 191 | { 192 | test "${_positionals_count}" -le 1 || _PRINT_HELP=yes die "FATAL ERROR: There were spurious positional arguments --- we expect between 0 and 1, but got ${_positionals_count} (the last one was: '${_last_positional}')." 1 193 | } 194 | 195 | 196 | assign_positional_args() 197 | { 198 | local _positional_name _shift_for=$1 199 | _positional_names="_arg_qjs_version " 200 | 201 | shift "$_shift_for" 202 | for _positional_name in ${_positional_names} 203 | do 204 | test $# -gt 0 || break 205 | eval "$_positional_name=\${1}" || die "Error during argument parsing, possibly an Argbash bug." 1 206 | shift 207 | done 208 | } 209 | 210 | parse_commandline "$@" 211 | handle_passed_args_count 212 | assign_positional_args 1 "${_positionals[@]}" 213 | 214 | # OTHER STUFF GENERATED BY Argbash 215 | # Validation of values 216 | 217 | 218 | ### END OF CODE GENERATED BY Argbash (sortof) ### ]) 219 | # [ <-- needed because of Argbash 220 | 221 | 222 | # vvv PLACE YOUR CODE HERE vvv 223 | 224 | # ensure version exist 225 | qjs_commit="${qjs_commits[${_arg_qjs_version}]}" 226 | if [ -z ${qjs_commit} ] 227 | then 228 | _PRINT_HELP=yes die "QuickJS version '${_arg_qjs_version}' is not supported" 229 | fi 230 | 231 | _PRINT_HELP=no 232 | 233 | build_docker_image() 234 | { 235 | _flag_verbose="" 236 | [ ${_arg_verbose} == "on" ] && _flag_verbose="-v" 237 | _flag_force_build_image="" 238 | [ ${_arg_force_build_image} == "on" ] && _flag_force_build_image="-f" 239 | 240 | ${script_dir}/scripts/build_docker_image.sh ${_flag_verbose} -a ${_arg_arch} ${_flag_force_build_image} || return 1 241 | 242 | return 0 243 | } 244 | 245 | build_and_export_package() 246 | { 247 | _image_name="quickjs-cross-compiler:${_arg_arch}" 248 | 249 | _flag_verbose="" 250 | [ ${_arg_verbose} == "on" ] && _flag_verbose="-v" 251 | args_qjs_ext_lib="" 252 | if [ ${_arg_ext_lib} == "on" ] 253 | then 254 | args_qjs_ext_lib="--ext-lib --ext-lib-version ${_arg_ext_lib_version}" 255 | fi 256 | args_extra_dir="" 257 | for a in ${_arg_extra_dir[@]} 258 | do 259 | args_extra_dir="${args_extra_dir} -e ${a}" 260 | done 261 | _flag_disable_upx="" 262 | [ ${_arg_upx} == "off" ] && _flag_disable_upx="--no-upx" 263 | 264 | _docker_cmd="./build_and_export_qjs.sh ${_flag_verbose} -a ${_arg_arch} ${args_qjs_ext_lib} ${args_extra_dir} ${_flag_disable_upx}" 265 | 266 | (mkdir -p ${_arg_packages_dir} && \ 267 | docker run --rm \ 268 | --mount type=bind,source="${script_dir}/../builder",target="/usr/local/src/quickjs-cross-compiler/builder" \ 269 | --mount type=bind,source="${_arg_packages_dir}",target="/usr/local/src/quickjs-cross-compiler/packages" \ 270 | ${_image_name} ${_docker_cmd}) || return 1 271 | return 0 272 | } 273 | 274 | build_docker_image || exit 1 275 | build_and_export_package || exit 1 276 | 277 | # ^^^ TERMINATE YOUR CODE BEFORE THE BOTTOM ARGBASH MARKER ^^^ 278 | 279 | # ] <-- needed because of Argbash 280 | -------------------------------------------------------------------------------- /docker/scripts/build_docker_image.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### 4 | # 5 | # Build a docker image which can be used to cross-compile QuickJS 6 | # Image will contain : 7 | # - musl.cc cross-compiler 8 | # - a built version of musl lib 9 | # 10 | ### 11 | 12 | script_dir="$(cd "$(dirname "$(readlink -f "$0")")" && pwd)" || { echo "Couldn't determine the script's running directory, which probably matters, bailing out" >&2; exit 2; } 13 | 14 | # Created by argbash-init v2.10.0 15 | # ARG_OPTIONAL_SINGLE([arch],[a],[target architecture],[x86_64]) 16 | # ARG_OPTIONAL_BOOLEAN([force],[f],[rebuild image even if it exists],[off]) 17 | # ARG_OPTIONAL_BOOLEAN([verbose],[v],[enable verbose mode],[off]) 18 | # ARG_TYPE_GROUP_SET([arch],[type string],[arch],[x86_64,i686,armv7l,aarch64]) 19 | # ARG_HELP([Build a Docker image which can be used to cross-compile QuickJS]) 20 | # ARGBASH_GO() 21 | # needed because of Argbash --> m4_ignore([ 22 | ### START OF CODE GENERATED BY Argbash v2.10.0 one line above ### 23 | # Argbash is a bash code generator used to get arguments parsing right. 24 | # Argbash is FREE SOFTWARE, see https://argbash.io for more info 25 | 26 | 27 | die() 28 | { 29 | local _ret="${2:-1}" 30 | test "${_PRINT_HELP:-no}" = yes && print_help >&2 31 | echo "$1" >&2 32 | exit "${_ret}" 33 | } 34 | 35 | # validators 36 | 37 | arch() 38 | { 39 | local _allowed=("x86_64" "i686" "armv7l" "aarch64") _seeking="$1" 40 | for element in "${_allowed[@]}" 41 | do 42 | test "$element" = "$_seeking" && echo "$element" && return 0 43 | done 44 | die "Value '$_seeking' (of argument '$2') doesn't match the list of allowed values: 'x86_64', 'i686', 'armv7l' and 'aarch64'" 4 45 | } 46 | 47 | 48 | begins_with_short_option() 49 | { 50 | local first_option all_short_options='afvh' 51 | first_option="${1:0:1}" 52 | test "$all_short_options" = "${all_short_options/$first_option/}" && return 1 || return 0 53 | } 54 | 55 | # THE DEFAULTS INITIALIZATION - OPTIONALS 56 | _arg_arch="x86_64" 57 | _arg_force="off" 58 | _arg_verbose="off" 59 | 60 | 61 | print_help() 62 | { 63 | printf '%s\n' "Build a Docker image which can be used to cross-compile QuickJS" 64 | printf 'Usage: %s [-a|--arch ] [-f|--(no-)force] [-v|--(no-)verbose] [-h|--help]\n' "$0" 65 | printf '\t%s\n' "-a, --arch: target architecture. Can be one of: 'x86_64', 'i686', 'armv7l' and 'aarch64' (default: 'x86_64')" 66 | printf '\t%s\n' "-f, --force, --no-force: rebuild image even if it exists (off by default)" 67 | printf '\t%s\n' "-v, --verbose, --no-verbose: enable verbose mode (off by default)" 68 | printf '\t%s\n' "-h, --help: Prints help" 69 | } 70 | 71 | 72 | parse_commandline() 73 | { 74 | while test $# -gt 0 75 | do 76 | _key="$1" 77 | case "$_key" in 78 | -a|--arch) 79 | test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 80 | _arg_arch="$(arch "$2" "arch")" || exit 1 81 | shift 82 | ;; 83 | --arch=*) 84 | _arg_arch="$(arch "${_key##--arch=}" "arch")" || exit 1 85 | ;; 86 | -a*) 87 | _arg_arch="$(arch "${_key##-a}" "arch")" || exit 1 88 | ;; 89 | -f|--no-force|--force) 90 | _arg_force="on" 91 | test "${1:0:5}" = "--no-" && _arg_force="off" 92 | ;; 93 | -f*) 94 | _arg_force="on" 95 | _next="${_key##-f}" 96 | if test -n "$_next" -a "$_next" != "$_key" 97 | then 98 | { begins_with_short_option "$_next" && shift && set -- "-f" "-${_next}" "$@"; } || die "The short option '$_key' can't be decomposed to ${_key:0:2} and -${_key:2}, because ${_key:0:2} doesn't accept value and '-${_key:2:1}' doesn't correspond to a short option." 99 | fi 100 | ;; 101 | -v|--no-verbose|--verbose) 102 | _arg_verbose="on" 103 | test "${1:0:5}" = "--no-" && _arg_verbose="off" 104 | ;; 105 | -v*) 106 | _arg_verbose="on" 107 | _next="${_key##-v}" 108 | if test -n "$_next" -a "$_next" != "$_key" 109 | then 110 | { begins_with_short_option "$_next" && shift && set -- "-v" "-${_next}" "$@"; } || die "The short option '$_key' can't be decomposed to ${_key:0:2} and -${_key:2}, because ${_key:0:2} doesn't accept value and '-${_key:2:1}' doesn't correspond to a short option." 111 | fi 112 | ;; 113 | -h|--help) 114 | print_help 115 | exit 0 116 | ;; 117 | -h*) 118 | print_help 119 | exit 0 120 | ;; 121 | *) 122 | _PRINT_HELP=yes die "FATAL ERROR: Got an unexpected argument '$1'" 1 123 | ;; 124 | esac 125 | shift 126 | done 127 | } 128 | 129 | parse_commandline "$@" 130 | 131 | # OTHER STUFF GENERATED BY Argbash 132 | # Validation of values 133 | 134 | 135 | ### END OF CODE GENERATED BY Argbash (sortof) ### ]) 136 | # [ <-- needed because of Argbash 137 | 138 | 139 | # vvv PLACE YOUR CODE HERE vvv 140 | 141 | # Build docker image 142 | build_image() 143 | { 144 | # check if image exist 145 | _image_name="quickjs-cross-compiler:${_arg_arch}" 146 | _image=$(docker images --format "{{.ID}}" --filter=reference="${_image_name}" | head -1) 147 | 148 | [ ${_arg_verbose} == "on" ] && echo "Building docker image for '${_arg_arch}'..." 149 | 150 | # no need to build image 151 | if ! [ -z ${_image} ] && [ ${_arg_force} == "off" ] 152 | then 153 | [ ${_arg_verbose} == "on" ] && echo "No need to build docker image for '${_arg_arch}'..." 154 | else 155 | docker build --build-arg arch=${_arg_arch} --no-cache --force-rm=true --rm=true -f ${script_dir}/../Dockerfile -t ${_image_name} ${script_dir}/../.. || return 1 156 | [ ${_arg_verbose} == "on" ] && echo "Successfully built docker image for '${_arg_arch}'" 157 | fi 158 | 159 | return 0 160 | } 161 | 162 | _PRINT_HELP=no 163 | 164 | build_image || die "Could not build docker image for '${_arg_arch}'" 165 | 166 | # ^^^ TERMINATE YOUR CODE BEFORE THE BOTTOM ARGBASH MARKER ^^^ 167 | 168 | # ] <-- needed because of Argbash 169 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-utils": { 4 | "inputs": { 5 | "systems": "systems" 6 | }, 7 | "locked": { 8 | "lastModified": 1710146030, 9 | "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", 10 | "owner": "numtide", 11 | "repo": "flake-utils", 12 | "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", 13 | "type": "github" 14 | }, 15 | "original": { 16 | "owner": "numtide", 17 | "repo": "flake-utils", 18 | "type": "github" 19 | } 20 | }, 21 | "nixpkgs": { 22 | "locked": { 23 | "lastModified": 1724479785, 24 | "narHash": "sha256-pP3Azj5d6M5nmG68Fu4JqZmdGt4S4vqI5f8te+E/FTw=", 25 | "owner": "nixos", 26 | "repo": "nixpkgs", 27 | "rev": "d0e1602ddde669d5beb01aec49d71a51937ed7be", 28 | "type": "github" 29 | }, 30 | "original": { 31 | "owner": "nixos", 32 | "ref": "nixos-unstable", 33 | "repo": "nixpkgs", 34 | "type": "github" 35 | } 36 | }, 37 | "root": { 38 | "inputs": { 39 | "flake-utils": "flake-utils", 40 | "nixpkgs": "nixpkgs" 41 | } 42 | }, 43 | "systems": { 44 | "locked": { 45 | "lastModified": 1681028828, 46 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 47 | "owner": "nix-systems", 48 | "repo": "default", 49 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 50 | "type": "github" 51 | }, 52 | "original": { 53 | "owner": "nix-systems", 54 | "repo": "default", 55 | "type": "github" 56 | } 57 | } 58 | }, 59 | "root": "root", 60 | "version": 7 61 | } 62 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "QuickJS Static Compiler"; 3 | 4 | inputs = { 5 | nixpkgs = { 6 | url = "github:nixos/nixpkgs/nixos-unstable"; 7 | }; 8 | 9 | flake-utils.url = "github:numtide/flake-utils"; 10 | }; 11 | 12 | outputs = { self, nixpkgs, flake-utils }: 13 | flake-utils.lib.eachSystem [ "x86_64-linux" "armv7l-linux" "aarch64-linux" ] (system: 14 | let 15 | pkgs = import nixpkgs { 16 | inherit system; 17 | }; 18 | 19 | highlight = text: "\\x1b[1;38;5;212m${text}\\x1b[0m"; 20 | 21 | qjs_version = "2025-04-26_1"; 22 | arch = 23 | if system == "x86_64-linux" then "x86_64" 24 | else if system == "armv7l-linux" then "armv7l" 25 | else if system == "aarch64-linux" then "aarch64" 26 | else "unknown-arch"; 27 | sha256 = 28 | if system == "x86_64-linux" then "sha256:12i025crfdggf2h2sr5lkfriwxdy98309b50mvkzfqk4f23kww70" 29 | else if system == "armv7l-linux" then "sha256:0imv0f9arajjxj5hapd09sn43mf79lswpgpdcqfaajnhcha4m592" 30 | else if system == "aarch64-linux" then "sha256:06y42w0ak9brapvwszm74qrgs5yhlkbcs44kj4anwnx9mmgdv3an" 31 | else "sha256:0000000000000000000000000000000000000000000000000000"; 32 | 33 | quickjsStatic = pkgs.stdenv.mkDerivation { 34 | name = "quickjs-static"; 35 | 36 | src = builtins.fetchTarball { 37 | url = "https://github.com/ctn-malone/quickjs-cross-compiler/releases/download/v${qjs_version}/quickjs.core.${qjs_version}.${arch}.tar.xz"; 38 | sha256 = sha256; 39 | }; 40 | 41 | configurePhase = false; 42 | buildPhase = false; 43 | 44 | installPhase = '' 45 | mkdir -p $out/bin 46 | cp -R $src/* $out/bin 47 | ''; 48 | }; 49 | 50 | in 51 | { 52 | 53 | packages.quickjs-static = quickjsStatic; 54 | 55 | defaultPackage = self.packages.${system}.quickjs-static; 56 | 57 | apps = { 58 | # interpreter 59 | default = { 60 | type = "app"; 61 | program = "${quickjsStatic}/bin/qjs.sh"; 62 | }; 63 | 64 | qjs = self.apps.${system}.default; 65 | 66 | # compiler 67 | qjsc = { 68 | type = "app"; 69 | program = "${quickjsStatic}/bin/qjsc.sh"; 70 | }; 71 | }; 72 | 73 | devShell = pkgs.mkShell { 74 | name = "quickjs-static"; 75 | 76 | buildInputs = [ 77 | pkgs.upx 78 | quickjsStatic 79 | ]; 80 | 81 | shellHook = '' 82 | echo -e "To compile a JS file, use ${highlight "qjsc.sh -o "}" 1>&2 83 | echo -e "To run a JS file, use ${highlight "qjs.sh "}" 1>&2 84 | ''; 85 | }; 86 | } 87 | ); 88 | } 89 | --------------------------------------------------------------------------------