/ README.md
README.md
  1  # Common parts of the build system used by Nimbus and related projects
  2  
  3  We focus on building Nim software on multiple platforms, without having to deal
  4  with language-specific package managers.
  5  
  6  We care about dependencies specified with commit-level accuracy (including the
  7  Nim compiler), reproducible builds, bisectable Git histories and self-contained
  8  projects that don't create dirs/files outside their main directory.
  9  
 10  We try to minimise complexity, but we will trade implementation complexity
 11  increases for a simpler user experience.
 12  
 13  ## Prerequisites
 14  
 15  GNU Make, Bash and the usual POSIX utilities.
 16  
 17  ## Usage
 18  
 19  Add this repository to your project as a Git submodule. You can use our handy shell script:
 20  
 21  ```bash
 22  curl -OLs https://raw.githubusercontent.com/status-im/nimbus-build-system/master/scripts/add_submodule.sh
 23  less add_submodule.sh # you do read random Internet scripts before running them, right?
 24  chmod 755 add_submodule.sh
 25  ./add_submodule.sh status-im/nimbus-build-system
 26  ```
 27  
 28  Or you can do it by hand:
 29  
 30  ```bash
 31  git submodule add https://github.com/status-im/nimbus-build-system.git vendor/nimbus-build-system
 32  # specify a branch
 33  git config -f .gitmodules submodule.vendor/nimbus-build-system.branch master
 34  # hide submodule working tree changes in `git diff`
 35  git config -f .gitmodules submodule.vendor/nimbus-build-system.ignore dirty
 36  ```
 37  
 38  Write your own top-level Makefile, taking our
 39  "[Makefile.superproject.example](./Makefile.superproject.example)" as an...
 40  example.
 41  
 42  See also the Makefiles we wrote for
 43  [Nimbus-eth1](https://github.com/status-im/nimbus-eth1),
 44  [Nimbus-eth2](https://github.com/status-im/nimbus-eth2),
 45  [nim-waku](https://github.com/status-im/nim-waku),
 46  [Stratus](https://github.com/status-im/nim-stratus),
 47  [nim-status-client](https://github.com/status-im/nim-status-client).
 48  
 49  Instruct your users to run `make update` after cloning your project, after a
 50  `git pull` or after switching branches.
 51  
 52  ## Make variables
 53  
 54  ### V
 55  
 56  Control the verbosity level. Defaults to 0 for a nice, quiet build.
 57  
 58  ```bash
 59  make V=1 # verbose
 60  make V=2 test # even more verbose
 61  ```
 62  
 63  ### LOG_LEVEL
 64  
 65  Set the [Chronicles log
 66  level](https://github.com/status-im/nim-chronicles#chronicles_log_level) to one
 67  of: TRACE, DEBUG, INFO, NOTICE, WARN, ERROR, FATAL, NONE.
 68  
 69  This Make variable is unset by default, which means that Chronicles' default
 70  kicks in (DEBUG in debug builds and INFO in release mode) or some
 71  application-specific default takes precedence.
 72  
 73  Note that this sets the compile-time log level. If runtime log level selection
 74  is implemented (which cannot have larger values than what was set at compile
 75  time), additional steps need to be taken to pass the proper command line
 76  argument to your binary.
 77  
 78  ```bash
 79  make LOG_LEVEL=DEBUG foo # this is the default
 80  make LOG_LEVEL=TRACE bar # log everything
 81  ```
 82  
 83  ### NIMFLAGS
 84  
 85  Pass arbitrary parameters to the Nim compiler. Uses an internal `NIM_PARAMS`
 86  variable that should not be overridden by the user.
 87  
 88  ```bash
 89  make NIMFLAGS="-d:release"
 90  ```
 91  
 92  Defaults to Nim parameters mirroring the selected verbosity and log level:
 93  
 94  ```bash
 95  make V=0 # NIMFLAGS="--verbosity:0 --hints:off"
 96  make V=1 LOG_LEVEL=TRACE # NIMFLAGS="--verbosity:1 -d:chronicles_log_level=TRACE"
 97  make V=2 # NIMFLAGS="--verbosity:2"
 98  ```
 99  
100  Projects using this build system may choose to add other default flags like
101  `-d:release` in their Makefiles (usually those that can't be placed in a
102  top-level "config.nims" or "nim.cfg"). This will be done by appending to the
103  internal variable:
104  
105  ```make
106  NIM_PARAMS += -d:release
107  ```
108  
109  ### CI_CACHE
110  
111  Specify a directory where Nim compiler binaries should be cached, in a CI service like AppVeyor:
112  
113  ```yml
114  build_script:
115    # the 32-bit build is done on a 64-bit image, so we need to override the architecture
116    - mingw32-make -j2 ARCH_OVERRIDE=%PLATFORM% CI_CACHE=NimBinaries update
117  ```
118  
119  ### USE_SYSTEM_NIM
120  
121  Use the system Nim instead of our shipped version (usually for testing Nim
122  devel versions). Defaults to 0. Setting it to 1 means you're on your own, when
123  it comes to support.
124  
125  `make USE_SYSTEM_NIM=1 test`
126  
127  ### PARTIAL_STATIC_LINKING
128  
129  Statically link some libraries (currently libgcc\_s and libpcre). Defaults to 0.
130  
131  This is useful when you can't statically link Glibc because you use NSS functions.
132  
133  `make PARTIAL_STATIC_LINKING=1 beacon_node`
134  
135  ### LINK_PCRE
136  
137  Link PCRE, defaults to 1.
138  
139  `make LINK_PCRE=0`
140  
141  ### QUICK_AND_DIRTY_COMPILER
142  
143  Skip some Nim compiler bootstrap iterations and tool building. Useful in
144  CI. Defaults to 0.
145  
146  `make QUICK_AND_DIRTY_COMPILER=1 build-nim`
147  
148  ### QUICK_AND_DIRTY_NIMBLE
149  
150  Build Nimble when it wouldn't be normally built as part of the tools. Only
151  useful with `QUICK_AND_DIRTY_COMPILER=1`. Defaults to 0.
152  
153  `make QUICK_AND_DIRTY_COMPILER=1 QUICK_AND_DIRTY_NIMBLE=1 build-nim`
154  
155  ### NIM_COMMIT
156  
157  Build and use a different Nim compiler version than the default one.
158  
159  Possible values: (partial) commit hashes, tags, branches and anything else recognised by `git checkout ...`.
160  
161  `make -j8 NIM_COMMIT="v1.2.6" build-nim`
162  
163  You also need to specify it when using this non-default Nim compiler version:
164  
165  `make -j8 NIM_COMMIT="v1.2.6" nimbus_beacon_node`
166  
167  ### EXCLUDED_NIM_PACKAGES
168  
169  List of relative paths (incomplete ones also work) to Git submodules that
170  should not end up as Nim packages in "vendor/.nimble" - usually because they
171  duplicate more high-level ones.
172  
173  For example, say we have:
174  
175  ```text
176  $ find vendor -name "nim-chronos" | sort
177  vendor/nim-chronos
178  vendor/nim-waku/vendor/nim-chronos
179  vendor/nim-waku/vendor/nim-dnsdisc/vendor/nim-chronos
180  ```
181  
182  We only want the top-level "vendor/nim-chronos", so we put the rest in
183  `EXCLUDED_NIM_PACKAGES`, in the top-level Makefile:
184  
185  ```text
186  EXCLUDED_NIM_PACKAGES := vendor/nim-waku/vendor/nim-chronos \
187  			 vendor/nim-waku/vendor/nimbus-build-system \
188  			 vendor/nim-waku/vendor/nim-dnsdisc/vendor
189  ```
190  
191  As you see, we can exclude all those "nim-dnsdisc" submodules with a single
192  line, because the pattern is not anchored during the match.
193  
194  ### OVERRIDE
195  
196  Whether to override any uncommitted changes to Git submodules during `make
197  update`. Defaults to 1, in order to keep the old behaviour for users building
198  from source.
199  
200  Set to 0 inside `make update-dev`, to help developers avoid losing work.
201  
202  ## Make targets
203  
204  ### build
205  
206  Internal target that creates the directory with the same name.
207  
208  ### sanity-checks
209  
210  Internal target used to check that a C compiler is installed.
211  
212  ### warn-update
213  
214  Internal target that checks if `make update` was executed for the current Git commit.
215  
216  ### warn-jobs
217  
218  Internal target that checks if Make's parallelism was enabled by specifying the number of jobs.
219  
220  ### deps-common
221  
222  Internal target that needs to be a dependency for a custom "deps" target which,
223  in turn, will be a dependency for various compilation targets.
224  
225  The superproject's Makefile would look like this:
226  
227  ```make
228  deps: | deps-common
229  	# Have custom deps? Add them above.
230  
231  # building Nim programs
232  foo bar: | build deps
233  	echo -e $(BUILD_MSG) "build/$@" && \
234  		$(ENV_SCRIPT) nim c -o:build/$@ $(NIM_PARAMS) "$@.nim"
235  ```
236  
237  The user should never have to run `make deps` directly.
238  
239  ### build-nim
240  
241  Internal target that builds the Nim compiler if it's not built yet or if the
242  corresponding submodule points to a newer commit than the existing binary.
243  
244  It's being executed as part of "update-common" and "$(NIM\_BINARY)" targets. It
245  may be executed directly, rarely, when testing new Nim versions.
246  
247  ### update-common
248  
249  Internal target that needs to become the dependency of a custom "update" target.
250  
251  ```make
252  update: | update-common
253  	# Do you need to do something extra for this target?
254  ```
255  
256  Initialises and updates all Git submodules, with various ugly hacks to account
257  for corner cases like submodules changing URLs or being replaced with regularly
258  committed files.
259  
260  Tell your users to run `make update` after cloning the superproject, after a
261  `git pull` and after changing branches or checking out older commits.
262  
263  ## update-dev
264  
265  Alternative to "update" for developers who want to avoid losing uncommitted
266  work in Git submodules. `make update-dev` simply runs `make OVERRIDE=0 update`.
267  
268  ### update-remote
269  
270  Dangerous target that updates all submodules to their latest remote commit.
271  
272  As you may imagine, it's usually necessary to roll back one or two of these
273  automatic bumps. You do it like this:
274  
275  ```bash
276  git submodule update --recursive vendor/news
277  ```
278  
279  ### clean-cross
280  
281  Confusingly named target that deletes libnatpmp and miniupnp objects and static
282  libraries. Useful when you're cross-compiling and don't want to `make clean`
283  and have to rebuild the compiler.
284  
285  ### clean-common
286  
287  Internal target that needs to be a dependency for a custom "clean" target that
288  deletes any additional build artefacts:
289  
290  ```make
291  clean: | clean-common
292  	rm -rf build/{foo,bar}
293  ```
294  
295  Don't run `make clean` if you don't really need to, since it also deletes the Nim compiler.
296  
297  Unlike C/C++ projects, we always recompile our Nim targets (because it's too
298  hard to tell Make what are all the files involved in the build process), so
299  there's no need to delete them to force a recompilation.
300  
301  ### mrproper
302  
303  Dangerous target that, in addition to depending on "clean", deletes the
304  "vendor" directory and any not-yet-pushed modification you may have in there.
305  Don't use it.
306  
307  ### github-ssh
308  
309  Changes submodule URLs, without affecting .gitmodules, so you connect to GitHub
310  using your SSH key - very useful when you have write access to some submodule
311  repos and you want to work on them without cloning them separately.
312  
313  ### status
314  
315  Run `git status` in all your submodules and in your superproject.
316  
317  ### ctags
318  
319  Run [Universal Ctags](https://github.com/universal-ctags/ctags) with a bunch of Nim-specific options.
320  
321  ### show-deps
322  
323  List all Git submodules, including the nested ones.
324  
325  ### fetch-dlls
326  
327  Windows-specific target. Downloads and unpacks in the "build" dir some DLLs we may not want to build ourselves (PCRE, RocksDB, libcurl, pdcurses, SQLite3, OpenSSL, zlib, etc.).
328  
329  ### nat-libs
330  
331  Build "libminiupnpc.a" and "libnatpmp.a" from [nim-nat-traversal](https://github.com/status-im/nim-nat-traversal)'s submodules - not included in this repo.
332  
333  ## Scripts
334  
335  ### add_submodule.sh
336  
337  Add a new Git submodule to your superproject, setting the branch to "master"
338  and hiding submodule working tree changes in `git diff`.
339  
340  Usage: `./add_submodule.sh some/repo [destdir]` # "destdir" defaults to "vendor/repo"
341  
342  Examples:
343  
344  `./add_submodule.sh status-im/nimbus-build-system`
345  
346  `./vendor/nimbus-build-system/scripts/add_submodule.sh status-im/nim-nat-traversal`
347  
348  ### build_nim.sh
349  
350  Build the Nim compiler and some associated tools, parallelising the
351  bootstrap-from-C phase, with binary caching and conditional recompilation
352  support (based on the timestamp of the latest commit in the Nim repo).
353  
354  Usage: `./build_nim.sh nim_dir csources_dir nimble_dir ci_cache_dir`
355  
356  This script is not usually used directly, but through the `update` target
357  (which depends on `update-common` which runs `build-nim`).
358  
359  Our `build-nim` target uses it like this:
360  
361  ```make
362  build-nim: | sanity-checks
363  	+ NIM_BUILD_MSG="$(BUILD_MSG) Nim compiler" \
364  		V=$(V) \
365  		CC=$(CC) \
366  		MAKE=$(MAKE) \
367  		ARCH_OVERRIDE=$(ARCH_OVERRIDE) \
368  		"$(CURDIR)/$(BUILD_SYSTEM_DIR)/scripts/build_nim.sh" "$(NIM_DIR)" ../Nim-csources ../nimble "$(CI_CACHE)"
369  ```
370  
371  Other Nim projects that don't use this build system use the script directly in their CI. From a ".travis.yml":
372  
373  ```yaml
374  install:
375    - curl -O -L -s -S https://raw.githubusercontent.com/status-im/nimbus-build-system/master/scripts/build_nim.sh
376    - env MAKE="make -j${NPROC}" bash build_nim.sh Nim csources dist/nimble NimBinaries
377    - export PATH="$PWD/Nim/bin:$PATH"
378  ```
379  
380  Or an ".appveyor.yml":
381  
382  ```yaml
383  install:
384    # [...]
385    - curl -O -L -s -S https://raw.githubusercontent.com/status-im/nimbus-build-system/master/scripts/build_nim.sh
386    - env MAKE="mingw32-make -j2" ARCH_OVERRIDE=%PLATFORM% bash build_nim.sh Nim csources dist/nimble NimBinaries
387    - SET PATH=%CD%\Nim\bin;%PATH%
388  ```
389  
390  Notice how the number of Make jobs is set through the "MAKE" env var.
391  
392  ### build_rocksdb.sh
393  
394  Builds RocksDB. No longer used.
395  
396  Usage: `./build_rocksdb.sh ci_cache_dir`
397  
398  ### create_nimble_link.sh
399  
400  Cheeky little script used to fake a Nimble package repository in the
401  `$(NIMBLE_DIR)` target (a dependency of `deps-common` which is a dependency of
402  `deps`):
403  
404  ```make
405  $(NIMBLE_DIR):
406  	mkdir -p $(NIMBLE_DIR)/pkgs
407  	NIMBLE_DIR="$(CURDIR)/$(NIMBLE_DIR)" PWD_CMD="$(PWD)" \
408  		git submodule foreach --quiet '$(CURDIR)/$(BUILD_SYSTEM_DIR)/scripts/create_nimble_link.sh "$$sm_path"'
409  ```
410  
411  That's how the Nim compiler knows how to find all these Nim packages we have in
412  our submodules: we set the "NIMBLE\_DIR" env var to the path of this fake
413  Nimble package repo.
414  
415  ### env.sh
416  
417  Script responsible for setting up environment variables and shell aliases
418  necessary for using this build system. It's being sourced by a script with the
419  same name in the superproject's top directory:
420  
421  ```bash
422  #!/usr/bin/env bash
423  
424  # We use ${BASH_SOURCE[0]} instead of $0 to allow sourcing this file
425  # and we fall back to a Zsh-specific special var to also support Zsh.
426  REL_PATH="$(dirname ${BASH_SOURCE[0]:-${(%):-%x}})"
427  ABS_PATH="$(cd ${REL_PATH}; pwd)"
428  source ${ABS_PATH}/vendor/nimbus-build-system/scripts/env.sh
429  ```
430  
431  Supported usage: `./env.sh nim --version`
432  
433  Unsupported usage: `source env.sh; nim --version`
434  
435  An interesting alias is `nimble` which calls the "nimble.sh" script which pretends to be Nimble:
436  
437  ```bash
438  cd vendor/nim-metrics
439  ../../env.sh nimble test
440  ```
441  
442  In order to get autocompletion and code navigation functionality working
443  properly in your text editor, you need the environment variables set by this script:
444  
445  ```bash
446  ./env.sh vim
447  ```
448  
449  ### nimble.sh
450  
451  Simple script that symlinks the first \*.nimble file it finds to \*.nims and
452  runs it using `nim`. Easier to access using the `nimble` alias in "env.sh".
453  
454  Of very limited use, it can execute \*.nimble targets, as long as there are no
455  "before install:" blocks that the real Nimble strips before doing the same thing we do.
456  
457  If you need the real Nimble, it's in "vendor/nimbus-build-system/vendor/Nim/bin/nimble".
458  
459  ## License
460  
461  Licensed and distributed under either of
462  
463  * MIT license: [LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT
464  
465  or
466  
467  * Apache License, Version 2.0, ([LICENSE-APACHEv2](LICENSE-APACHEv2) or http://www.apache.org/licenses/LICENSE-2.0)
468  
469  at your option. These files may not be copied, modified, or distributed except according to those terms.
470