The sixteenth batch
[git/gitster.git] / meson.build
blobc043a79dca74f2e28bc4ae7127e23212d7055af4
1 # Meson build system
2 # ==================
4 # The Meson build system is an alternative to our Makefile that you can use to
5 # build, test and install Git. Using Meson results in a couple of benefits:
7 #  - Out-of-tree builds.
8 #  - Better integration into IDEs.
9 #  - Easy-to-use autoconfiguration of available features on your system.
11 # To use Meson from the command line you need to have both Meson and Ninja
12 # installed. Alternatively, if you do not have Python available on your system,
13 # you can also use Muon instead of Meson and Samurai instead of Ninja, both of
14 # which are drop-ins replacement that only depend on C.
16 # Basic usage
17 # ===========
19 # In the most trivial case, you can configure, build and install Git like this:
21 #  1. Set up the build directory. This only needs to happen once per build
22 #     directory you want to have. You can also configure multiple different
23 #     build directories with different configurations.
25 #      $ meson setup build/
27 #     The build directory gets ignored by Git automatically as Meson will write
28 #     a ".gitignore" file into it. From hereon, we will assume that you execute
29 #     commands inside this build directory.
31 # 2. Compile Git. You can either use Meson, Ninja or Samurai to do this, so all
32 #    of the following invocations are equivalent:
34 #      $ meson compile
35 #      $ ninja
36 #      $ samu
38 #   The different invocations should ultimately not make much of a difference.
39 #   Using Meson also works with other generators though, like when the build
40 #   directory has been set up for use with Microsoft Visual Studio.
42 #   Ninja and Samurai use multiple jobs by default, scaling with the number of
43 #   processor cores available. You can pass the `-jN` flag to change this.
45 #   Meson automatically picks up ccache and sccache when these are installed
46 #   when setting up the build directory. You can override this behaviour when
47 #   setting up the build directory by setting the `CC` environment variable to
48 #   your desired compiler.
50 # 3. Execute tests. Again, you can either use Meson, Ninja or Samurai to do this:
52 #      $ meson test
53 #      $ ninja test
54 #      $ samu test
56 #   It is recommended to use Meson in this case though as it also provides you
57 #   additional features that the other build systems don't have available.
58 #   You can e.g. pass additional arguments to the test executables or run
59 #   individual tests:
61 #      # Execute the t0000-basic integration test and t-reftable-stack unit test.
62 #      $ meson test t0000-basic t-reftable-stack
64 #      # Execute all reftable unit tests.
65 #      $ meson test t-reftable-*
67 #      # Execute all tests and stop with the first failure.
68 #      $ meson test --maxfail 1
70 #      # Execute single test interactively such that features like `debug ()` work.
71 #      $ meson test -i --test-args='-ix' t1400-update-ref
73 #      # Execute all benchmarks.
74 #      $ meson test -i --benchmark
76 #      # Execute single benchmark.
77 #      $ meson test -i --benchmark p0000-*
79 #   Test execution (but not benchmark execution) is parallelized by default and
80 #   scales with the number of processor cores available. You can change the
81 #   number of processes by passing the `-jN` flag to `meson test`.
83 # 4. Install the Git distribution. Again, this can be done via Meson, Ninja or
84 #    Samurai:
86 #      $ meson install
87 #      $ ninja install
88 #      $ samu install
90 #    The prefix into which Git shall be installed is defined when setting up
91 #    the build directory. More on that in the "Configuration" section.
93 # Meson supports multiple backends. The default backend generates Ninja build
94 # instructions, but it also supports the generation of Microsoft Visual
95 # Studio solutions as well as Xcode projects by passing the `--backend` option
96 # to `meson setup`. IDEs like Eclipse and Visual Studio Code provide plugins to
97 # import Meson files directly.
99 # Configuration
100 # =============
102 # The exact configuration of Git is determined when setting up the build
103 # directory via `meson setup`. Unless told otherwise, Meson will automatically
104 # detect the availability of various bits and pieces. There are two different
105 # kinds of options that can be used to further tweak the build:
107 #   - Built-in options provided by Meson.
109 #   - Options defined by the project in the "meson_options.txt" file.
111 # Both kinds of options can be inspected by running `meson configure` in the
112 # build directory, which will give you a list of the current value for all
113 # options.
115 # Options can be configured either when setting up the build directory or can
116 # be changed in preexisting build directories:
118 #      # Set up a new build directory with optimized settings that will be
119 #      # installed into an alternative prefix.
120 #      $ meson setup --buildtype release --optimization 3 --strip --prefix=/home/$USER build
122 #      # Set up a new build directory with a higher warning level. Level 2 is
123 #      # mostly equivalent to setting DEVELOPER=1, level 3 and "everything"
124 #      # will enable even more warnings.
125 #      $ meson setup -Dwarning_level=2 build
127 #      # Set up a new build directory with 'address' and 'undefined' sanitizers
128 #      # using Clang.
129 #      $ CC=clang meson setup -Db_sanitize=address,undefined build
131 #      # Disable tests in a preexisting build directory.
132 #      $ meson configure -Dtests=false
134 #      # Disable features based on Python
135 #      $ meson configure -Dpython=disabled
137 # Options have a type like booleans, choices, strings or features. Features are
138 # somewhat special as they can have one of three values: enabled, disabled or
139 # auto. While the first two values are self-explanatory, "auto" will enable or
140 # disable the feature based on the availability of prerequisites to support it.
141 # Python-based features for example will be enabled automatically when a Python
142 # interpreter could be found. The default value of such features can be changed
143 # via `meson setup --auto-features={enabled,disabled,auto}`, which will set the
144 # value of all features with a value of "auto" to the provided one by default.
146 # It is also possible to store a set of configuration options in machine files.
147 # This can be useful in case you regularly want to reuse the same set of options:
149 #   [binaries]
150 #   c = ['clang']
151 #   ar = ['ar']
153 #   [project options]
154 #   gettext = 'disabled'
155 #   default_editor = 'vim'
157 #   [built-in options]
158 #   b_lto = true
159 #   b_sanitize = 'address,undefined'
161 # These machine files can be passed to `meson setup` via the `--native-file`
162 # option.
164 # Cross compilation
165 # =================
167 # Machine files can also be used in the context of cross-compilation to
168 # describe the target machine as well as the cross-compiler toolchain that
169 # shall be used. An example machine file could look like the following:
171 #   [binaries]
172 #   c = 'x86_64-w64-mingw32-gcc'
173 #   cpp = 'x86_64-w64-mingw32-g++'
174 #   ar = 'x86_64-w64-mingw32-ar'
175 #   windres = 'x86_64-w64-mingw32-windres'
176 #   strip = 'x86_64-w64-mingw32-strip'
177 #   exe_wrapper = 'wine64'
178 #   sh = 'C:/Program Files/Git for Windows/usr/bin/sh.exe'
180 #   [host_machine]
181 #   system = 'windows'
182 #   cpu_family = 'x86_64'
183 #   cpu = 'x86_64'
184 #   endian = 'little'
186 # These machine files can be passed to `meson setup` via the `--cross-file`
187 # option.
189 # Note that next to the cross-compiler toolchain, the `[binaries]` section is
190 # also used to locate a couple of binaries that will be built into Git. This
191 # includes `sh`, `python` and `perl`, so when cross-compiling Git you likely
192 # want to set these binary paths in addition to the cross-compiler toolchain
193 # binaries.
195 # Subproject wrappers
196 # ===================
198 # Subproject wrappers are a feature provided by Meson that allows the automatic
199 # fallback to a "wrapped" dependency in case the dependency is not provided by
200 # the system. For example if the system is lacking curl, then Meson will use
201 # "subprojects/curl.wrap" to set up curl as a subproject and compile and link
202 # the dependency into Git itself. This is especially helpful on systems like
203 # Windows, where you typically don't have such dependencies installed.
205 # The use of subproject wrappers can be disabled by executing `meson setup`
206 # with the `--wrap-mode nofallback` option.
208 project('git', 'c',
209   meson_version: '>=0.61.0',
210   # The version is only of cosmetic nature, so if we cannot find a shell yet we
211   # simply don't set up a version at all. This may be the case for example on
212   # Windows systems, where we first have to bootstrap the host environment.
213   version: find_program('sh', native: true, required: false).found() ? run_command(
214     'GIT-VERSION-GEN', meson.current_source_dir(), '--format=@GIT_VERSION@',
215     capture: true,
216     check: true,
217   ).stdout().strip() : 'unknown',
218   # Git requires C99 with GNU extensions, which of course isn't supported by
219   # MSVC. Funny enough, C99 doesn't work with MSVC either, as it has only
220   # learned to define __STDC_VERSION__ with C11 and later. We thus require
221   # GNU C99 and fall back to C11. Meson only learned to handle the fallback
222   # with version 1.3.0, so on older versions we use GNU C99 unconditionally.
223   default_options: meson.version().version_compare('>=1.3.0') ? ['c_std=gnu99,c11'] : ['c_std=gnu99'],
226 fs = import('fs')
228 program_path = []
229 if get_option('sane_tool_path').length() != 0
230   program_path = get_option('sane_tool_path')
231 elif host_machine.system() == 'windows'
232   # Git for Windows provides all the tools we need to build Git.
233   program_path = [ 'C:/Program Files/Git/bin', 'C:/Program Files/Git/usr/bin' ]
234 endif
236 cygpath = find_program('cygpath', dirs: program_path, native: true, required: false)
237 diff = find_program('diff', dirs: program_path, native: true)
238 git = find_program('git', dirs: program_path, native: true, required: false)
239 sed = find_program('sed', dirs: program_path, native: true)
240 shell = find_program('sh', dirs: program_path, native: true)
241 tar = find_program('tar', dirs: program_path, native: true)
242 time = find_program('time', dirs: program_path, required: get_option('benchmarks'))
244 # Detect the target shell that is used by Git at runtime. Note that we prefer
245 # "/bin/sh" over a PATH-based lookup, which provides a working shell on most
246 # supported systems. This path is also the default shell path used by our
247 # Makefile. This lookup can be overridden via `program_path`.
248 target_shell = find_program('/bin/sh', 'sh', dirs: program_path, native: false)
250 # Sanity-check that programs required for the build exist.
251 foreach tool : ['cat', 'cut', 'grep', 'sort', 'tr', 'uname']
252   find_program(tool, dirs: program_path, native: true)
253 endforeach
255 script_environment = environment()
256 foreach path : program_path
257   script_environment.prepend('PATH', path)
258 endforeach
260 # The environment used by GIT-VERSION-GEN. Note that we explicitly override
261 # environment variables that might be set by the user. This is by design so
262 # that we always use whatever Meson has configured instead of what is present
263 # in the environment.
264 version_gen_environment = script_environment
265 version_gen_environment.set('GIT_BUILT_FROM_COMMIT', get_option('built_from_commit'))
266 version_gen_environment.set('GIT_DATE', get_option('build_date'))
267 version_gen_environment.set('GIT_USER_AGENT', get_option('user_agent'))
268 version_gen_environment.set('GIT_VERSION', get_option('version'))
270 compiler = meson.get_compiler('c')
272 libgit_sources = [
273   'abspath.c',
274   'add-interactive.c',
275   'add-patch.c',
276   'advice.c',
277   'alias.c',
278   'alloc.c',
279   'apply.c',
280   'archive-tar.c',
281   'archive-zip.c',
282   'archive.c',
283   'attr.c',
284   'base85.c',
285   'bisect.c',
286   'blame.c',
287   'blob.c',
288   'bloom.c',
289   'branch.c',
290   'bulk-checkin.c',
291   'bundle-uri.c',
292   'bundle.c',
293   'cache-tree.c',
294   'cbtree.c',
295   'chdir-notify.c',
296   'checkout.c',
297   'chunk-format.c',
298   'color.c',
299   'column.c',
300   'combine-diff.c',
301   'commit-graph.c',
302   'commit-reach.c',
303   'commit.c',
304   'common-exit.c',
305   'common-init.c',
306   'compat/nonblock.c',
307   'compat/obstack.c',
308   'compat/open.c',
309   'compat/terminal.c',
310   'compiler-tricks/not-constant.c',
311   'config.c',
312   'connect.c',
313   'connected.c',
314   'convert.c',
315   'copy.c',
316   'credential.c',
317   'csum-file.c',
318   'ctype.c',
319   'date.c',
320   'decorate.c',
321   'delta-islands.c',
322   'diagnose.c',
323   'diff-delta.c',
324   'diff-merges.c',
325   'diff-lib.c',
326   'diff-no-index.c',
327   'diff.c',
328   'diffcore-break.c',
329   'diffcore-delta.c',
330   'diffcore-order.c',
331   'diffcore-pickaxe.c',
332   'diffcore-rename.c',
333   'diffcore-rotate.c',
334   'dir-iterator.c',
335   'dir.c',
336   'editor.c',
337   'entry.c',
338   'environment.c',
339   'ewah/bitmap.c',
340   'ewah/ewah_bitmap.c',
341   'ewah/ewah_io.c',
342   'ewah/ewah_rlw.c',
343   'exec-cmd.c',
344   'fetch-negotiator.c',
345   'fetch-pack.c',
346   'fmt-merge-msg.c',
347   'fsck.c',
348   'fsmonitor.c',
349   'fsmonitor-ipc.c',
350   'fsmonitor-settings.c',
351   'gettext.c',
352   'git-zlib.c',
353   'gpg-interface.c',
354   'graph.c',
355   'grep.c',
356   'hash-lookup.c',
357   'hash.c',
358   'hashmap.c',
359   'help.c',
360   'hex.c',
361   'hex-ll.c',
362   'hook.c',
363   'ident.c',
364   'json-writer.c',
365   'kwset.c',
366   'levenshtein.c',
367   'line-log.c',
368   'line-range.c',
369   'linear-assignment.c',
370   'list-objects-filter-options.c',
371   'list-objects-filter.c',
372   'list-objects.c',
373   'lockfile.c',
374   'log-tree.c',
375   'loose.c',
376   'ls-refs.c',
377   'mailinfo.c',
378   'mailmap.c',
379   'match-trees.c',
380   'mem-pool.c',
381   'merge-blobs.c',
382   'merge-ll.c',
383   'merge-ort.c',
384   'merge-ort-wrappers.c',
385   'merge.c',
386   'midx.c',
387   'midx-write.c',
388   'name-hash.c',
389   'negotiator/default.c',
390   'negotiator/noop.c',
391   'negotiator/skipping.c',
392   'notes-cache.c',
393   'notes-merge.c',
394   'notes-utils.c',
395   'notes.c',
396   'object-file-convert.c',
397   'object-file.c',
398   'object-name.c',
399   'object.c',
400   'odb.c',
401   'oid-array.c',
402   'oidmap.c',
403   'oidset.c',
404   'oidtree.c',
405   'pack-bitmap-write.c',
406   'pack-bitmap.c',
407   'pack-check.c',
408   'pack-mtimes.c',
409   'pack-objects.c',
410   'pack-revindex.c',
411   'pack-write.c',
412   'packfile.c',
413   'pager.c',
414   'parallel-checkout.c',
415   'parse.c',
416   'parse-options-cb.c',
417   'parse-options.c',
418   'patch-delta.c',
419   'patch-ids.c',
420   'path.c',
421   'path-walk.c',
422   'pathspec.c',
423   'pkt-line.c',
424   'preload-index.c',
425   'pretty.c',
426   'prio-queue.c',
427   'progress.c',
428   'promisor-remote.c',
429   'prompt.c',
430   'protocol.c',
431   'protocol-caps.c',
432   'prune-packed.c',
433   'pseudo-merge.c',
434   'quote.c',
435   'range-diff.c',
436   'reachable.c',
437   'read-cache.c',
438   'rebase-interactive.c',
439   'rebase.c',
440   'ref-filter.c',
441   'reflog-walk.c',
442   'reflog.c',
443   'refs.c',
444   'refs/debug.c',
445   'refs/files-backend.c',
446   'refs/reftable-backend.c',
447   'refs/iterator.c',
448   'refs/packed-backend.c',
449   'refs/ref-cache.c',
450   'refspec.c',
451   'reftable/basics.c',
452   'reftable/error.c',
453   'reftable/block.c',
454   'reftable/blocksource.c',
455   'reftable/iter.c',
456   'reftable/merged.c',
457   'reftable/pq.c',
458   'reftable/record.c',
459   'reftable/stack.c',
460   'reftable/system.c',
461   'reftable/table.c',
462   'reftable/tree.c',
463   'reftable/writer.c',
464   'remote.c',
465   'replace-object.c',
466   'repo-settings.c',
467   'repository.c',
468   'rerere.c',
469   'reset.c',
470   'resolve-undo.c',
471   'revision.c',
472   'run-command.c',
473   'send-pack.c',
474   'sequencer.c',
475   'serve.c',
476   'server-info.c',
477   'setup.c',
478   'shallow.c',
479   'sideband.c',
480   'sigchain.c',
481   'sparse-index.c',
482   'split-index.c',
483   'stable-qsort.c',
484   'statinfo.c',
485   'strbuf.c',
486   'streaming.c',
487   'string-list.c',
488   'strmap.c',
489   'strvec.c',
490   'sub-process.c',
491   'submodule-config.c',
492   'submodule.c',
493   'symlinks.c',
494   'tag.c',
495   'tempfile.c',
496   'thread-utils.c',
497   'tmp-objdir.c',
498   'trace.c',
499   'trace2.c',
500   'trace2/tr2_cfg.c',
501   'trace2/tr2_cmd_name.c',
502   'trace2/tr2_ctr.c',
503   'trace2/tr2_dst.c',
504   'trace2/tr2_sid.c',
505   'trace2/tr2_sysenv.c',
506   'trace2/tr2_tbuf.c',
507   'trace2/tr2_tgt_event.c',
508   'trace2/tr2_tgt_normal.c',
509   'trace2/tr2_tgt_perf.c',
510   'trace2/tr2_tls.c',
511   'trace2/tr2_tmr.c',
512   'trailer.c',
513   'transport-helper.c',
514   'transport.c',
515   'tree-diff.c',
516   'tree-walk.c',
517   'tree.c',
518   'unpack-trees.c',
519   'upload-pack.c',
520   'url.c',
521   'urlmatch.c',
522   'usage.c',
523   'userdiff.c',
524   'utf8.c',
525   'varint.c',
526   'version.c',
527   'versioncmp.c',
528   'walker.c',
529   'wildmatch.c',
530   'worktree.c',
531   'wrapper.c',
532   'write-or-die.c',
533   'ws.c',
534   'wt-status.c',
535   'xdiff-interface.c',
536   'xdiff/xdiffi.c',
537   'xdiff/xemit.c',
538   'xdiff/xhistogram.c',
539   'xdiff/xmerge.c',
540   'xdiff/xpatience.c',
541   'xdiff/xprepare.c',
542   'xdiff/xutils.c',
545 libgit_sources += custom_target(
546   input: 'command-list.txt',
547   output: 'command-list.h',
548   command: [shell, meson.current_source_dir() + '/generate-cmdlist.sh', meson.current_source_dir(), '@OUTPUT@'],
549   env: script_environment,
552 builtin_sources = [
553   'builtin/add.c',
554   'builtin/am.c',
555   'builtin/annotate.c',
556   'builtin/apply.c',
557   'builtin/archive.c',
558   'builtin/backfill.c',
559   'builtin/bisect.c',
560   'builtin/blame.c',
561   'builtin/branch.c',
562   'builtin/bugreport.c',
563   'builtin/bundle.c',
564   'builtin/cat-file.c',
565   'builtin/check-attr.c',
566   'builtin/check-ignore.c',
567   'builtin/check-mailmap.c',
568   'builtin/check-ref-format.c',
569   'builtin/checkout--worker.c',
570   'builtin/checkout-index.c',
571   'builtin/checkout.c',
572   'builtin/clean.c',
573   'builtin/clone.c',
574   'builtin/column.c',
575   'builtin/commit-graph.c',
576   'builtin/commit-tree.c',
577   'builtin/commit.c',
578   'builtin/config.c',
579   'builtin/count-objects.c',
580   'builtin/credential-cache--daemon.c',
581   'builtin/credential-cache.c',
582   'builtin/credential-store.c',
583   'builtin/credential.c',
584   'builtin/describe.c',
585   'builtin/diagnose.c',
586   'builtin/diff-files.c',
587   'builtin/diff-index.c',
588   'builtin/diff-pairs.c',
589   'builtin/diff-tree.c',
590   'builtin/diff.c',
591   'builtin/difftool.c',
592   'builtin/fast-export.c',
593   'builtin/fast-import.c',
594   'builtin/fetch-pack.c',
595   'builtin/fetch.c',
596   'builtin/fmt-merge-msg.c',
597   'builtin/for-each-ref.c',
598   'builtin/for-each-repo.c',
599   'builtin/fsck.c',
600   'builtin/fsmonitor--daemon.c',
601   'builtin/gc.c',
602   'builtin/get-tar-commit-id.c',
603   'builtin/grep.c',
604   'builtin/hash-object.c',
605   'builtin/help.c',
606   'builtin/hook.c',
607   'builtin/index-pack.c',
608   'builtin/init-db.c',
609   'builtin/interpret-trailers.c',
610   'builtin/log.c',
611   'builtin/ls-files.c',
612   'builtin/ls-remote.c',
613   'builtin/ls-tree.c',
614   'builtin/mailinfo.c',
615   'builtin/mailsplit.c',
616   'builtin/merge-base.c',
617   'builtin/merge-file.c',
618   'builtin/merge-index.c',
619   'builtin/merge-ours.c',
620   'builtin/merge-recursive.c',
621   'builtin/merge-tree.c',
622   'builtin/merge.c',
623   'builtin/mktag.c',
624   'builtin/mktree.c',
625   'builtin/multi-pack-index.c',
626   'builtin/mv.c',
627   'builtin/name-rev.c',
628   'builtin/notes.c',
629   'builtin/pack-objects.c',
630   'builtin/pack-refs.c',
631   'builtin/patch-id.c',
632   'builtin/prune-packed.c',
633   'builtin/prune.c',
634   'builtin/pull.c',
635   'builtin/push.c',
636   'builtin/range-diff.c',
637   'builtin/read-tree.c',
638   'builtin/rebase.c',
639   'builtin/receive-pack.c',
640   'builtin/reflog.c',
641   'builtin/refs.c',
642   'builtin/remote-ext.c',
643   'builtin/remote-fd.c',
644   'builtin/remote.c',
645   'builtin/repack.c',
646   'builtin/replace.c',
647   'builtin/replay.c',
648   'builtin/rerere.c',
649   'builtin/reset.c',
650   'builtin/rev-list.c',
651   'builtin/rev-parse.c',
652   'builtin/revert.c',
653   'builtin/rm.c',
654   'builtin/send-pack.c',
655   'builtin/shortlog.c',
656   'builtin/show-branch.c',
657   'builtin/show-index.c',
658   'builtin/show-ref.c',
659   'builtin/sparse-checkout.c',
660   'builtin/stash.c',
661   'builtin/stripspace.c',
662   'builtin/submodule--helper.c',
663   'builtin/symbolic-ref.c',
664   'builtin/tag.c',
665   'builtin/unpack-file.c',
666   'builtin/unpack-objects.c',
667   'builtin/update-index.c',
668   'builtin/update-ref.c',
669   'builtin/update-server-info.c',
670   'builtin/upload-archive.c',
671   'builtin/upload-pack.c',
672   'builtin/var.c',
673   'builtin/verify-commit.c',
674   'builtin/verify-pack.c',
675   'builtin/verify-tag.c',
676   'builtin/worktree.c',
677   'builtin/write-tree.c',
680 third_party_excludes = [
681   ':!contrib',
682   ':!compat/inet_ntop.c',
683   ':!compat/inet_pton.c',
684   ':!compat/nedmalloc',
685   ':!compat/obstack.*',
686   ':!compat/poll',
687   ':!compat/regex',
688   ':!sha1collisiondetection',
689   ':!sha1dc',
690   ':!t/unit-tests/clar',
691   ':!t/t[0-9][0-9][0-9][0-9]*',
692   ':!xdiff',
695 headers_to_check = []
696 if git.found() and fs.exists(meson.project_source_root() / '.git')
697   foreach header : run_command(git, '-C', meson.project_source_root(), 'ls-files', '--deduplicate', '*.h', third_party_excludes, check: true).stdout().split()
698     headers_to_check += header
699   endforeach
700 endif
702 if not get_option('breaking_changes')
703   builtin_sources += 'builtin/pack-redundant.c'
704 endif
706 builtin_sources += custom_target(
707   output: 'config-list.h',
708   command: [
709     shell,
710     meson.current_source_dir() + '/generate-configlist.sh',
711     meson.current_source_dir(),
712     '@OUTPUT@',
713   ],
714   env: script_environment,
717 builtin_sources += custom_target(
718   input: 'Documentation/githooks.adoc',
719   output: 'hook-list.h',
720   command: [
721     shell,
722     meson.current_source_dir() + '/generate-hooklist.sh',
723     meson.current_source_dir(),
724     '@OUTPUT@',
725   ],
726   env: script_environment,
729 # This contains the variables for GIT-BUILD-OPTIONS, which we use to propagate
730 # build options to our tests.
731 build_options_config = configuration_data()
732 build_options_config.set('GIT_INTEROP_MAKE_OPTS', '')
733 build_options_config.set_quoted('GIT_PERF_LARGE_REPO', get_option('benchmark_large_repo'))
734 build_options_config.set('GIT_PERF_MAKE_COMMAND', '')
735 build_options_config.set('GIT_PERF_MAKE_OPTS', '')
736 build_options_config.set_quoted('GIT_PERF_REPEAT_COUNT', get_option('benchmark_repeat_count').to_string())
737 build_options_config.set_quoted('GIT_PERF_REPO', get_option('benchmark_repo'))
738 build_options_config.set('GIT_TEST_CMP_USE_COPIED_CONTEXT', '')
739 build_options_config.set('GIT_TEST_INDEX_VERSION', '')
740 build_options_config.set('GIT_TEST_OPTS', '')
741 build_options_config.set('GIT_TEST_PERL_FATAL_WARNINGS', '')
742 build_options_config.set_quoted('GIT_TEST_UTF8_LOCALE', get_option('test_utf8_locale'))
743 build_options_config.set_quoted('LOCALEDIR', fs.as_posix(get_option('prefix') / get_option('localedir')))
744 build_options_config.set_quoted('GITWEBDIR', fs.as_posix(get_option('prefix') / get_option('datadir') / 'gitweb'))
746 if get_option('sane_tool_path').length() != 0
747   sane_tool_path = (host_machine.system() == 'windows' ? ';' : ':').join(get_option('sane_tool_path'))
748   build_options_config.set_quoted('BROKEN_PATH_FIX', 's|^\# @BROKEN_PATH_FIX@$|git_broken_path_fix "' + sane_tool_path + '"|')
749 else
750   build_options_config.set_quoted('BROKEN_PATH_FIX', '/^\# @BROKEN_PATH_FIX@$/d')
751 endif
753 test_output_directory = get_option('test_output_directory')
754 if test_output_directory == ''
755   test_output_directory = meson.project_build_root() / 'test-output'
756 endif
758 # These variables are used for building libgit.a.
759 libgit_c_args = [
760   '-DBINDIR="' + get_option('bindir') + '"',
761   '-DDEFAULT_GIT_TEMPLATE_DIR="' + get_option('datadir') / 'git-core/templates' + '"',
762   '-DFALLBACK_RUNTIME_PREFIX="' + get_option('prefix') + '"',
763   '-DGIT_HOST_CPU="' + host_machine.cpu_family() + '"',
764   '-DGIT_HTML_PATH="' + get_option('datadir') / 'doc/git-doc"',
765   '-DGIT_INFO_PATH="' + get_option('infodir') + '"',
766   '-DGIT_LOCALE_PATH="' + get_option('localedir') + '"',
767   '-DGIT_MAN_PATH="' + get_option('mandir') + '"',
768   '-DPAGER_ENV="' + get_option('pager_environment') + '"',
769   '-DSHELL_PATH="' + fs.as_posix(target_shell.full_path()) + '"',
772 system_attributes = get_option('gitattributes')
773 if system_attributes != ''
774   libgit_c_args += '-DETC_GITATTRIBUTES="' + system_attributes + '"'
775 else
776   libgit_c_args += '-DETC_GITATTRIBUTES="' + get_option('sysconfdir') / 'gitattributes"'
777 endif
779 system_config = get_option('gitconfig')
780 if system_config != ''
781   libgit_c_args += '-DETC_GITCONFIG="' + system_config + '"'
782 else
783   libgit_c_args += '-DETC_GITCONFIG="' + get_option('sysconfdir') / 'gitconfig"'
784 endif
786 editor_opt = get_option('default_editor')
787 if editor_opt != '' and editor_opt != 'vi'
788   libgit_c_args += '-DDEFAULT_EDITOR="' + editor_opt + '"'
789 endif
791 pager_opt = get_option('default_pager')
792 if pager_opt != '' and pager_opt != 'less'
793   libgit_c_args += '-DDEFAULT_PAGER="' + pager_opt + '"'
794 endif
796 help_format_opt = get_option('default_help_format')
797 if help_format_opt == 'platform'
798   if host_machine.system() == 'windows'
799     help_format_opt = 'html'
800   else
801     help_format_opt = 'man'
802   endif
803 endif
804 if help_format_opt != 'man'
805     libgit_c_args += '-DDEFAULT_HELP_FORMAT="' + help_format_opt + '"'
806 endif
808 libgit_include_directories = [ '.' ]
809 libgit_dependencies = [ ]
811 # Treat any warning level above 1 the same as we treat DEVELOPER=1 in our
812 # Makefile.
813 if get_option('warning_level') in ['2','3', 'everything'] and compiler.get_argument_syntax() == 'gcc'
814   foreach cflag : [
815     '-Wcomma',
816     '-Wdeclaration-after-statement',
817     '-Wformat-security',
818     '-Wold-style-definition',
819     '-Woverflow',
820     '-Wpointer-arith',
821     '-Wstrict-prototypes',
822     '-Wunreachable-code',
823     '-Wunused',
824     '-Wvla',
825     '-Wwrite-strings',
826     '-fno-common',
827     '-Wtautological-constant-out-of-range-compare',
828     # If a function is public, there should be a prototype and the right
829     # header file should be included. If not, it should be static.
830     '-Wmissing-prototypes',
831     # These are disabled because we have these all over the place.
832     '-Wno-empty-body',
833     '-Wno-missing-field-initializers',
834   ]
835     if compiler.has_argument(cflag)
836       libgit_c_args += cflag
837     endif
838   endforeach
839 endif
841 if get_option('breaking_changes')
842   build_options_config.set('WITH_BREAKING_CHANGES', 'YesPlease')
843   libgit_c_args += '-DWITH_BREAKING_CHANGES'
844 else
845   build_options_config.set('WITH_BREAKING_CHANGES', '')
846 endif
848 if get_option('b_sanitize').contains('address')
849   build_options_config.set('SANITIZE_ADDRESS', 'YesCompiledWithIt')
850 else
851   build_options_config.set('SANITIZE_ADDRESS', '')
852 endif
853 if get_option('b_sanitize').contains('leak')
854   build_options_config.set('SANITIZE_LEAK', 'YesCompiledWithIt')
855 else
856   build_options_config.set('SANITIZE_LEAK', '')
857 endif
858 if get_option('b_sanitize').contains('undefined')
859   libgit_c_args += '-DSHA1DC_FORCE_ALIGNED_ACCESS'
860 endif
862 executable_suffix = ''
863 if host_machine.system() == 'cygwin' or host_machine.system() == 'windows'
864   executable_suffix = '.exe'
865   libgit_c_args += '-DSTRIP_EXTENSION="' + executable_suffix + '"'
866 endif
867 build_options_config.set_quoted('X', executable_suffix)
869 # Python is not used for our build system, but exclusively for git-p4.
870 # Consequently we only need to determine whether Python is available for the
871 # build target.
872 target_python = find_program('python3', native: false, required: get_option('python'))
873 if target_python.found()
874   build_options_config.set('NO_PYTHON', '')
875 else
876   libgit_c_args += '-DNO_PYTHON'
877   build_options_config.set('NO_PYTHON', '1')
878 endif
880 # Perl is used for two different things: our test harness and to provide some
881 # features. It is optional if you want to neither execute tests nor use any of
882 # these optional features.
883 perl_required = get_option('perl')
884 if get_option('benchmarks').enabled() or get_option('gitweb').enabled() or 'netrc' in get_option('credential_helpers')
885   perl_required = true
886 endif
888 # Note that we only set NO_PERL if the Perl features were disabled by the user.
889 # It may not be set when we have found Perl, but only use it to run tests.
891 # At the time of writing, executing `perl --version` results in a string
892 # similar to the following output:
894 #     This is perl 5, version 40, subversion 0 (v5.40.0) built for x86_64-linux-thread-multi
896 # Meson picks up the "40" as version number instead of using "v5.40.0"
897 # due to the regular expression it uses. This got fixed in Meson 1.7.0,
898 # but meanwhile we have to either use `-V:version` instead of `--version`,
899 # which we can do starting with Meson 1.5.0 and newer, or we have to
900 # match against the minor version.
901 if meson.version().version_compare('>=1.5.0')
902   perl = find_program('perl', dirs: program_path, native: true, required: perl_required, version: '>=5.26.0', version_argument: '-V:version')
903   target_perl = find_program('perl', dirs: program_path, native: false, required: perl.found(), version: '>=5.26.0', version_argument: '-V:version')
904 else
905   perl = find_program('perl', dirs: program_path, native: true, required: perl_required, version: '>=26')
906   target_perl = find_program('perl', dirs: program_path, native: false, required: perl.found(), version: '>=26')
907 endif
908 perl_features_enabled = perl.found() and get_option('perl').allowed()
909 if perl_features_enabled
910   build_options_config.set('NO_PERL', '')
912   if get_option('runtime_prefix')
913     build_options_config.set('PERL_LOCALEDIR', '')
914   else
915     build_options_config.set_quoted('PERL_LOCALEDIR', fs.as_posix(get_option('prefix') / get_option('localedir')))
916   endif
918   if get_option('perl_cpan_fallback')
919     build_options_config.set('NO_PERL_CPAN_FALLBACKS', '')
920   else
921     build_options_config.set_quoted('NO_PERL_CPAN_FALLBACKS', 'YesPlease')
922   endif
923 else
924   libgit_c_args += '-DNO_PERL'
925   build_options_config.set('NO_PERL', '1')
926   build_options_config.set('PERL_LOCALEDIR', '')
927   build_options_config.set('NO_PERL_CPAN_FALLBACKS', '')
928 endif
930 zlib_backend = get_option('zlib_backend')
931 if zlib_backend in ['auto', 'zlib-ng']
932   zlib_ng = dependency('zlib-ng', required: zlib_backend == 'zlib-ng')
933   if zlib_ng.found()
934     zlib_backend = 'zlib-ng'
935     libgit_c_args += '-DHAVE_ZLIB_NG'
936     libgit_dependencies += zlib_ng
937   endif
938 endif
939 if zlib_backend in ['auto', 'zlib']
940   zlib = dependency('zlib', default_options: ['default_library=static', 'tests=disabled'])
941   if zlib.version().version_compare('<1.2.0')
942     libgit_c_args += '-DNO_DEFLATE_BOUND'
943   endif
944   zlib_backend = 'zlib'
945   libgit_dependencies += zlib
946 endif
948 threads = dependency('threads', required: false)
949 if threads.found()
950   libgit_dependencies += threads
951   build_options_config.set('NO_PTHREADS', '')
952 else
953   libgit_c_args += '-DNO_PTHREADS'
954   build_options_config.set('NO_PTHREADS', '1')
955 endif
957 msgfmt = find_program('msgfmt', dirs: program_path, native: true, required: false)
958 gettext_option = get_option('gettext').disable_auto_if(not msgfmt.found())
959 if not msgfmt.found() and gettext_option.enabled()
960   error('Internationalization via libintl requires msgfmt')
961 endif
963 if gettext_option.allowed() and host_machine.system() == 'darwin' and get_option('macos_use_homebrew_gettext')
964   if host_machine.cpu_family() == 'x86_64'
965     libintl_prefix = '/usr/local'
966   elif host_machine.cpu_family() == 'aarch64'
967     libintl_prefix = '/opt/homebrew'
968   else
969     error('Homebrew workaround not supported on current architecture')
970   endif
972   intl = compiler.find_library('intl', dirs: libintl_prefix / 'lib', required: gettext_option)
973   if intl.found()
974     intl = declare_dependency(
975       dependencies: intl,
976       include_directories: libintl_prefix / 'include',
977     )
978   endif
979 else
980   intl = dependency('intl', required: gettext_option)
981 endif
982 if intl.found()
983   libgit_dependencies += intl
984   build_options_config.set('NO_GETTEXT', '')
985   build_options_config.set('USE_GETTEXT_SCHEME', '')
987   # POSIX nowadays requires `nl_langinfo()`, but some systems still don't have
988   # the function available. On such systems we instead fall back to libcharset.
989   # On native Windows systems we use our own emulation.
990   if host_machine.system() != 'windows' and not compiler.has_function('nl_langinfo')
991     libcharset = compiler.find_library('charset', required: true)
992     libgit_dependencies += libcharset
993     libgit_c_args += '-DHAVE_LIBCHARSET_H'
994   endif
995 else
996   libgit_c_args += '-DNO_GETTEXT'
997   build_options_config.set('NO_GETTEXT', '1')
998   build_options_config.set('USE_GETTEXT_SCHEME', 'fallthrough')
999 endif
1001 iconv = dependency('iconv', required: get_option('iconv'))
1002 if iconv.found()
1003   libgit_dependencies += iconv
1004   build_options_config.set('NO_ICONV', '')
1006   have_old_iconv = false
1007   if not compiler.compiles('''
1008     #include <iconv.h>
1010     extern size_t iconv(iconv_t cd,
1011                         char **inbuf, size_t *inbytesleft,
1012                         char **outbuf, size_t *outbytesleft);
1013   ''', name: 'old iconv interface', dependencies: [iconv])
1014     libgit_c_args += '-DOLD_ICONV'
1015     have_old_iconv = true
1016   endif
1018   iconv_omits_bom_source = '''#
1019     #include <iconv.h>
1021     int main(int argc, const char **argv)
1022     {
1023   '''
1024   if have_old_iconv
1025     iconv_omits_bom_source += '''
1026       typedef const char *iconv_ibp;
1027     '''
1028   else
1029     iconv_omits_bom_source += '''
1030       typedef char *iconv_ibp;
1031     '''
1032   endif
1033   iconv_omits_bom_source += '''
1034       int v;
1035       iconv_t conv;
1036       char in[] = "a"; iconv_ibp pin = in;
1037       char out[20] = ""; char *pout = out;
1038       size_t isz = sizeof in;
1039       size_t osz = sizeof out;
1041       conv = iconv_open("UTF-16", "UTF-8");
1042       iconv(conv, &pin, &isz, &pout, &osz);
1043       iconv_close(conv);
1044       v = (unsigned char)(out[0]) + (unsigned char)(out[1]);
1045       return v != 0xfe + 0xff;
1046     }
1047   '''
1049   if compiler.run(iconv_omits_bom_source,
1050     dependencies: iconv,
1051     name: 'iconv omits BOM',
1052   ).returncode() != 0
1053     libgit_c_args += '-DICONV_OMITS_BOM'
1054   endif
1055 else
1056   libgit_c_args += '-DNO_ICONV'
1057   build_options_config.set('NO_ICONV', '1')
1058 endif
1060 # can't use enable_auto_if() because it is only available in meson 1.1
1061 if host_machine.system() == 'windows' and get_option('pcre2').allowed()
1062   pcre2_feature = true
1063 else
1064   pcre2_feature = get_option('pcre2')
1065 endif
1066 pcre2 = dependency('libpcre2-8', required: pcre2_feature, default_options: ['default_library=static', 'test=false'])
1067 if pcre2.found() and pcre2.type_name() != 'internal' and host_machine.system() == 'darwin'
1068   # macOS installs a broken system package, double check
1069   if not compiler.has_header('pcre2.h', dependencies: pcre2)
1070     if pcre2_feature.enabled()
1071       pcre2_fallback = ['pcre2', 'libpcre2_8']
1072     else
1073       pcre2_fallback = []
1074     endif
1075     # Attempt to fallback or replace with not-found-dependency
1076     pcre2 = dependency('', required: false, fallback: pcre2_fallback, default_options: ['default_library=static', 'test=false'])
1077     if not pcre2.found()
1078       if pcre2_feature.enabled()
1079         error('only a broken pcre2 install found and pcre2 is required')
1080       else
1081         warning('broken pcre2 install found, disabling pcre2 feature')
1082       endif
1083     endif
1084   endif
1085 endif
1087 if pcre2.found()
1088   libgit_dependencies += pcre2
1089   libgit_c_args += '-DUSE_LIBPCRE2'
1090   build_options_config.set('USE_LIBPCRE2', '1')
1091 else
1092   build_options_config.set('USE_LIBPCRE2', '')
1093 endif
1095 curl = dependency('libcurl', version: '>=7.21.3', required: get_option('curl'), default_options: ['default_library=static', 'tests=disabled', 'tool=disabled'])
1096 use_curl_for_imap_send = false
1097 if curl.found()
1098   if curl.version().version_compare('>=7.34.0')
1099     libgit_c_args += '-DUSE_CURL_FOR_IMAP_SEND'
1100     use_curl_for_imap_send = true
1101   endif
1103   # Most executables don't have to link against libcurl, but we still need its
1104   # include directories so that we can resolve LIBCURL_VERSION in "help.c".
1105   libgit_dependencies += curl.partial_dependency(includes: true)
1106   build_options_config.set('NO_CURL', '')
1107 else
1108   libgit_c_args += '-DNO_CURL'
1109   build_options_config.set('NO_CURL', '1')
1110 endif
1112 expat = dependency('expat', required: get_option('expat'), default_options: ['default_library=static', 'build_tests=false'])
1113 if expat.found()
1114   libgit_dependencies += expat
1116   if expat.version().version_compare('<=1.2')
1117     libgit_c_args += '-DEXPAT_NEEDS_XMLPARSE_H'
1118   endif
1119   build_options_config.set('NO_EXPAT', '')
1120 else
1121   libgit_c_args += '-DNO_EXPAT'
1122   build_options_config.set('NO_EXPAT', '1')
1123 endif
1125 if not compiler.has_header('sys/select.h')
1126   libgit_c_args += '-DNO_SYS_SELECT_H'
1127 endif
1129 has_poll_h = compiler.has_header('poll.h')
1130 if not has_poll_h
1131   libgit_c_args += '-DNO_POLL_H'
1132 endif
1134 has_sys_poll_h = compiler.has_header('sys/poll.h')
1135 if not has_sys_poll_h
1136   libgit_c_args += '-DNO_SYS_POLL_H'
1137 endif
1139 if not has_poll_h and not has_sys_poll_h
1140   libgit_c_args += '-DNO_POLL'
1141   libgit_sources += 'compat/poll/poll.c'
1142   libgit_include_directories += 'compat/poll'
1143 endif
1145 if not compiler.has_header('inttypes.h')
1146   libgit_c_args += '-DNO_INTTYPES_H'
1147 endif
1149 if compiler.has_header('alloca.h')
1150   libgit_c_args += '-DHAVE_ALLOCA_H'
1151 endif
1153 # Windows has libgen.h and a basename implementation, but we still need our own
1154 # implementation to threat things like drive prefixes specially.
1155 if host_machine.system() == 'windows' or not compiler.has_header('libgen.h')
1156   libgit_c_args += '-DNO_LIBGEN_H'
1157   libgit_sources += 'compat/basename.c'
1158 endif
1160 if compiler.has_header('paths.h')
1161   libgit_c_args += '-DHAVE_PATHS_H'
1162 endif
1164 if compiler.has_header('strings.h')
1165   libgit_c_args += '-DHAVE_STRINGS_H'
1166 endif
1168 networking_dependencies = [ ]
1169 if host_machine.system() == 'windows'
1170   winsock = compiler.find_library('ws2_32', required: false)
1171   if winsock.found()
1172     networking_dependencies += winsock
1173   endif
1174 else
1175   networking_dependencies += [
1176     compiler.find_library('nsl', required: false),
1177     compiler.find_library('resolv', required: false),
1178     compiler.find_library('socket', required: false),
1179   ]
1180 endif
1181 libgit_dependencies += networking_dependencies
1183 if host_machine.system() != 'windows'
1184   foreach symbol : ['inet_ntop', 'inet_pton', 'hstrerror']
1185     if not compiler.has_function(symbol, dependencies: networking_dependencies)
1186       libgit_c_args += '-DNO_' + symbol.to_upper()
1187       libgit_sources += 'compat/' + symbol + '.c'
1188     endif
1189   endforeach
1190 endif
1192 has_ipv6 = compiler.has_function('getaddrinfo', dependencies: networking_dependencies)
1193 if not has_ipv6
1194   libgit_c_args += '-DNO_IPV6'
1195 endif
1197 if not compiler.compiles('''
1198   #ifdef _WIN32
1199   # include <winsock2.h>
1200   #else
1201   # include <sys/types.h>
1202   # include <sys/socket.h>
1203   #endif
1205   void func(void)
1206   {
1207     struct sockaddr_storage x;
1208   }
1209 ''', name: 'struct sockaddr_storage')
1210   if has_ipv6
1211     libgit_c_args += '-Dsockaddr_storage=sockaddr_in6'
1212   else
1213     libgit_c_args += '-Dsockaddr_storage=sockaddr_in'
1214   endif
1215 endif
1217 if compiler.has_function('socket', dependencies: networking_dependencies)
1218   libgit_sources += [
1219     'unix-socket.c',
1220     'unix-stream-server.c',
1221   ]
1222   build_options_config.set('NO_UNIX_SOCKETS', '')
1223 else
1224   libgit_c_args += '-DNO_UNIX_SOCKETS'
1225   build_options_config.set('NO_UNIX_SOCKETS', '1')
1226 endif
1228 if host_machine.system() == 'darwin'
1229   libgit_sources += 'compat/precompose_utf8.c'
1230   libgit_c_args += '-DPRECOMPOSE_UNICODE'
1231   libgit_c_args += '-DPROTECT_HFS_DEFAULT'
1232 endif
1234 # Configure general compatibility wrappers.
1235 if host_machine.system() == 'cygwin'
1236   libgit_sources += [
1237     'compat/win32/path-utils.c',
1238   ]
1239 elif host_machine.system() == 'windows'
1240   libgit_sources += [
1241     'compat/winansi.c',
1242     'compat/win32/dirent.c',
1243     'compat/win32/flush.c',
1244     'compat/win32/path-utils.c',
1245     'compat/win32/pthread.c',
1246     'compat/win32/syslog.c',
1247     'compat/win32mmap.c',
1248     'compat/nedmalloc/nedmalloc.c',
1249   ]
1251   libgit_c_args += [
1252     '-DDETECT_MSYS_TTY',
1253     '-DENSURE_MSYSTEM_IS_SET',
1254     '-DNATIVE_CRLF',
1255     '-DNOGDI',
1256     '-DNO_POSIX_GOODIES',
1257     '-DWIN32',
1258     '-D_CONSOLE',
1259     '-D_CONSOLE_DETECT_MSYS_TTY',
1260     '-D__USE_MINGW_ANSI_STDIO=0',
1261   ]
1263   libgit_dependencies += compiler.find_library('ntdll')
1264   libgit_include_directories += 'compat/win32'
1265   if compiler.get_id() == 'msvc'
1266     libgit_include_directories += 'compat/vcbuild/include'
1267     libgit_sources += 'compat/msvc.c'
1268   else
1269     libgit_sources += 'compat/mingw.c'
1270   endif
1271 endif
1273 if host_machine.system() == 'linux'
1274   libgit_sources += 'compat/linux/procinfo.c'
1275 elif host_machine.system() == 'windows'
1276   libgit_sources += 'compat/win32/trace2_win32_process_info.c'
1277 else
1278   libgit_sources += 'compat/stub/procinfo.c'
1279 endif
1281 if host_machine.system() == 'cygwin' or host_machine.system() == 'windows'
1282   libgit_c_args += [
1283     '-DUNRELIABLE_FSTAT',
1284     '-DMMAP_PREVENTS_DELETE',
1285     '-DOBJECT_CREATION_MODE=1',
1286   ]
1287 endif
1289 # Configure the simple-ipc subsystem required fro the fsmonitor.
1290 if host_machine.system() == 'windows'
1291   libgit_sources += [
1292     'compat/simple-ipc/ipc-shared.c',
1293     'compat/simple-ipc/ipc-win32.c',
1294   ]
1295   libgit_c_args += '-DSUPPORTS_SIMPLE_IPC'
1296 else
1297   libgit_sources += [
1298     'compat/simple-ipc/ipc-shared.c',
1299     'compat/simple-ipc/ipc-unix-socket.c',
1300   ]
1301   libgit_c_args += '-DSUPPORTS_SIMPLE_IPC'
1302 endif
1304 fsmonitor_backend = ''
1305 if host_machine.system() == 'windows'
1306   fsmonitor_backend = 'win32'
1307 elif host_machine.system() == 'darwin'
1308   fsmonitor_backend = 'darwin'
1309   libgit_dependencies += dependency('CoreServices')
1310 endif
1311 if fsmonitor_backend != ''
1312   libgit_c_args += '-DHAVE_FSMONITOR_DAEMON_BACKEND'
1313   libgit_c_args += '-DHAVE_FSMONITOR_OS_SETTINGS'
1315   libgit_sources += [
1316     'compat/fsmonitor/fsm-health-' + fsmonitor_backend + '.c',
1317     'compat/fsmonitor/fsm-ipc-' + fsmonitor_backend + '.c',
1318     'compat/fsmonitor/fsm-listen-' + fsmonitor_backend + '.c',
1319     'compat/fsmonitor/fsm-path-utils-' + fsmonitor_backend + '.c',
1320     'compat/fsmonitor/fsm-settings-' + fsmonitor_backend + '.c',
1321   ]
1322 endif
1323 build_options_config.set_quoted('FSMONITOR_DAEMON_BACKEND', fsmonitor_backend)
1324 build_options_config.set_quoted('FSMONITOR_OS_SETTINGS', fsmonitor_backend)
1326 if not get_option('b_sanitize').contains('address') and get_option('regex').allowed() and compiler.has_header('regex.h') and compiler.get_define('REG_STARTEND', prefix: '#include <regex.h>') != ''
1327   build_options_config.set('NO_REGEX', '')
1329   if compiler.get_define('REG_ENHANCED', prefix: '#include <regex.h>') != ''
1330     libgit_c_args += '-DUSE_ENHANCED_BASIC_REGULAR_EXPRESSIONS'
1331     libgit_sources += 'compat/regcomp_enhanced.c'
1332   endif
1333 elif not get_option('regex').enabled()
1334   libgit_c_args += [
1335     '-DNO_REGEX',
1336     '-DGAWK',
1337     '-DNO_MBSUPPORT',
1338   ]
1339   build_options_config.set('NO_REGEX', '1')
1340   libgit_sources += 'compat/regex/regex.c'
1341   libgit_include_directories += 'compat/regex'
1342 else
1343     error('Native regex support requested but not found')
1344 endif
1346 # setitimer and friends are provided by compat/mingw.c.
1347 if host_machine.system() != 'windows'
1348   if not compiler.compiles('''
1349     #include <sys/time.h>
1350     void func(void)
1351     {
1352       struct itimerval value;
1353     }
1354   ''', name: 'struct itimerval')
1355     libgit_c_args += '-DNO_STRUCT_ITIMERVAL'
1356     libgit_c_args += '-DNO_SETITIMER'
1357   elif not compiler.has_function('setitimer')
1358     libgit_c_args += '-DNO_SETITIMER'
1359   endif
1360 endif
1362 if compiler.has_member('struct stat', 'st_mtimespec.tv_nsec', prefix: '#include <sys/stat.h>')
1363   libgit_c_args += '-DUSE_ST_TIMESPEC'
1364 elif not compiler.has_member('struct stat', 'st_mtim.tv_nsec', prefix: '#include <sys/stat.h>')
1365   libgit_c_args += '-DNO_NSEC'
1366 endif
1368 if not compiler.has_member('struct stat', 'st_blocks', prefix: '#include <sys/stat.h>')
1369   libgit_c_args += '-DNO_ST_BLOCKS_IN_STRUCT_STAT'
1370 endif
1372 if not compiler.has_member('struct dirent', 'd_type', prefix: '#include <dirent.h>')
1373   libgit_c_args += '-DNO_D_TYPE_IN_DIRENT'
1374 endif
1376 if not compiler.has_member('struct passwd', 'pw_gecos', prefix: '#include <pwd.h>')
1377   libgit_c_args += '-DNO_GECOS_IN_PWENT'
1378 endif
1380 checkfuncs = {
1381   'strcasestr' : ['strcasestr.c'],
1382   'memmem' : ['memmem.c'],
1383   'strlcpy' : ['strlcpy.c'],
1384   'strtoull' : [],
1385   'setenv' : ['setenv.c'],
1386   'mkdtemp' : ['mkdtemp.c'],
1387   'initgroups' : [],
1388   'strtoumax' : ['strtoumax.c', 'strtoimax.c'],
1389   'pread' : ['pread.c'],
1392 if host_machine.system() == 'windows'
1393   libgit_c_args += '-DUSE_WIN32_MMAP'
1394 else
1395   checkfuncs += {
1396     'mmap' : ['mmap.c'],
1397     # provided by compat/mingw.c.
1398     'unsetenv' : ['unsetenv.c'],
1399     # provided by compat/mingw.c.
1400     'getpagesize' : [],
1401   }
1402 endif
1404 foreach func, impls : checkfuncs
1405   if not compiler.has_function(func)
1406     libgit_c_args += '-DNO_' + func.to_upper()
1407     foreach impl : impls
1408       libgit_sources += 'compat/' + impl
1409     endforeach
1410   endif
1411 endforeach
1413 if compiler.has_function('sync_file_range')
1414   libgit_c_args += '-DHAVE_SYNC_FILE_RANGE'
1415 endif
1417 if not compiler.has_function('strdup')
1418   libgit_c_args += '-DOVERRIDE_STRDUP'
1419   libgit_sources += 'compat/strdup.c'
1420 endif
1422 if not compiler.has_function('qsort')
1423   libgit_c_args += '-DINTERNAL_QSORT'
1424 endif
1425 libgit_sources += 'compat/qsort_s.c'
1427 if compiler.has_function('getdelim')
1428   libgit_c_args += '-DHAVE_GETDELIM'
1429 endif
1432 if compiler.has_function('clock_gettime')
1433   libgit_c_args += '-DHAVE_CLOCK_GETTIME'
1434 endif
1436 if compiler.compiles('''
1437   #include <time.h>
1439   void func(void)
1440   {
1441     clockid_t id = CLOCK_MONOTONIC;
1442   }
1443 ''', name: 'monotonic clock')
1444   libgit_c_args += '-DHAVE_CLOCK_MONOTONIC'
1445 endif
1447 has_bsd_sysctl = false
1448 if compiler.has_header('sys/sysctl.h')
1449   if compiler.compiles('''
1450     #include <stddef.h>
1451     #include <sys/sysctl.h>
1453     void func(void)
1454     {
1455       int val, mib[2] = { 0 };
1456       size_t len = sizeof(val);
1457       sysctl(mib, 2, &val, &len, NULL, 0);
1458     }
1459   ''', name: 'BSD sysctl')
1460     libgit_c_args += '-DHAVE_BSD_SYSCTL'
1461     has_bsd_sysctl = true
1462   endif
1463 endif
1465 if not has_bsd_sysctl
1466   if compiler.has_member('struct sysinfo', 'totalram', prefix: '#include <sys/sysinfo.h>')
1467     libgit_c_args += '-DHAVE_SYSINFO'
1468   endif
1469 endif
1471 if not meson.is_cross_build() and compiler.run('''
1472   #include <stdio.h>
1474   int main(int argc, const char **argv)
1475   {
1476     FILE *f = fopen(".", "r");
1477     return f ? 0 : 1;
1478   }
1479 ''', name: 'fread reads directories').returncode() == 0
1480   libgit_c_args += '-DFREAD_READS_DIRECTORIES'
1481   libgit_sources += 'compat/fopen.c'
1482 endif
1484 if not meson.is_cross_build() and fs.exists('/dev/tty')
1485   libgit_c_args += '-DHAVE_DEV_TTY'
1486 endif
1488 csprng_backend = get_option('csprng_backend')
1489 https_backend = get_option('https_backend')
1490 sha1_backend = get_option('sha1_backend')
1491 sha1_unsafe_backend = get_option('sha1_unsafe_backend')
1492 sha256_backend = get_option('sha256_backend')
1494 security_framework = dependency('Security', required: 'CommonCrypto' in [https_backend, sha1_backend, sha1_unsafe_backend])
1495 core_foundation_framework = dependency('CoreFoundation', required: security_framework.found())
1496 if https_backend == 'auto' and security_framework.found()
1497   https_backend = 'CommonCrypto'
1498 endif
1500 openssl_required = 'openssl' in [csprng_backend, https_backend, sha1_backend, sha1_unsafe_backend, sha256_backend]
1501 openssl = dependency('openssl',
1502   required: openssl_required,
1503   allow_fallback: openssl_required or https_backend == 'auto',
1504   default_options: ['default_library=static'],
1506 if https_backend == 'auto' and openssl.found()
1507   https_backend = 'openssl'
1508 endif
1510 if https_backend == 'CommonCrypto'
1511   libgit_dependencies += security_framework
1512   libgit_dependencies += core_foundation_framework
1513   libgit_c_args += '-DAPPLE_COMMON_CRYPTO'
1514 elif https_backend == 'openssl'
1515   libgit_dependencies += openssl
1516 else
1517   # We either couldn't find any dependencies with 'auto' or the user requested
1518   # 'none'. Both cases are benign.
1519   https_backend = 'none'
1520 endif
1522 if https_backend != 'openssl'
1523   libgit_c_args += '-DNO_OPENSSL'
1524 endif
1526 if sha1_backend == 'sha1dc'
1527   libgit_c_args += '-DSHA1_DC'
1528   libgit_c_args += '-DSHA1DC_NO_STANDARD_INCLUDES=1'
1529   libgit_c_args += '-DSHA1DC_INIT_SAFE_HASH_DEFAULT=0'
1530   libgit_c_args += '-DSHA1DC_CUSTOM_INCLUDE_SHA1_C="git-compat-util.h"'
1531   libgit_c_args += '-DSHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C="git-compat-util.h"'
1533   libgit_sources += [
1534     'sha1dc_git.c',
1535     'sha1dc/sha1.c',
1536     'sha1dc/ubc_check.c',
1537   ]
1538 endif
1539 if sha1_backend == 'CommonCrypto' or sha1_unsafe_backend == 'CommonCrypto'
1540   if sha1_backend == 'CommonCrypto'
1541     libgit_c_args += '-DSHA1_APPLE'
1542   endif
1543   if sha1_unsafe_backend == 'CommonCrypto'
1544     libgit_c_args += '-DSHA1_APPLE_UNSAFE'
1545   endif
1547   libgit_c_args += '-DCOMMON_DIGEST_FOR_OPENSSL'
1548   # Apple CommonCrypto requires chunking
1549   libgit_c_args += '-DSHA1_MAX_BLOCK_SIZE=1024L*1024L*1024L'
1550 endif
1551 if sha1_backend == 'openssl' or sha1_unsafe_backend == 'openssl'
1552   if sha1_backend == 'openssl'
1553     libgit_c_args += '-DSHA1_OPENSSL'
1554   endif
1555   if sha1_unsafe_backend == 'openssl'
1556     libgit_c_args += '-DSHA1_OPENSSL_UNSAFE'
1557   endif
1559   libgit_dependencies += openssl
1560 endif
1561 if sha1_backend == 'block' or sha1_unsafe_backend == 'block'
1562   if sha1_backend == 'block'
1563     libgit_c_args += '-DSHA1_BLK'
1564   endif
1565   if sha1_unsafe_backend == 'block'
1566     libgit_c_args += '-DSHA1_BLK_UNSAFE'
1567   endif
1569   libgit_sources += 'block-sha1/sha1.c'
1570 endif
1572 if sha256_backend == 'openssl'
1573   libgit_c_args += '-DSHA256_OPENSSL'
1574   libgit_dependencies += openssl
1575 elif sha256_backend == 'nettle'
1576   nettle = dependency('nettle')
1577   libgit_dependencies += nettle
1578   libgit_c_args += '-DSHA256_NETTLE'
1579 elif sha256_backend == 'gcrypt'
1580   gcrypt = dependency('gcrypt')
1581   libgit_dependencies += gcrypt
1582   libgit_c_args += '-DSHA256_GCRYPT'
1583 elif sha256_backend == 'block'
1584   libgit_c_args += '-DSHA256_BLK'
1585   libgit_sources += 'sha256/block/sha256.c'
1586 else
1587   error('Unhandled SHA256 backend ' + sha256_backend)
1588 endif
1590 # Backends are ordered to reflect our preference for more secure and faster
1591 # ones over the ones that are less so.
1592 if csprng_backend in ['auto', 'arc4random'] and compiler.has_header_symbol('stdlib.h', 'arc4random_buf', required: csprng_backend == 'arc4random')
1593   libgit_c_args += '-DHAVE_ARC4RANDOM'
1594   csprng_backend = 'arc4random'
1595 elif csprng_backend in ['auto', 'arc4random_bsd'] and compiler.has_header_symbol('bsd/stdlib.h', 'arc4random_buf', required: csprng_backend == 'arc4random_bsd')
1596   libgit_c_args += '-DHAVE_ARC4RANDOM_BSD'
1597   csprng_backend = 'arc4random_bsd'
1598 elif csprng_backend in ['auto', 'getrandom'] and compiler.has_header_symbol('sys/random.h', 'getrandom', required: csprng_backend == 'getrandom')
1599   libgit_c_args += '-DHAVE_GETRANDOM'
1600   csprng_backend = 'getrandom'
1601 elif csprng_backend in ['auto', 'getentropy'] and compiler.has_header_symbol('unistd.h', 'getentropy', required: csprng_backend == 'getentropy')
1602   libgit_c_args += '-DHAVE_GETENTROPY'
1603   csprng_backend = 'getentropy'
1604 elif csprng_backend in ['auto', 'rtlgenrandom'] and compiler.has_header_symbol('ntsecapi.h', 'RtlGenRandom', prefix: '#include <windows.h>', required: csprng_backend == 'rtlgenrandom')
1605   libgit_c_args += '-DHAVE_RTLGENRANDOM'
1606   csprng_backend = 'rtlgenrandom'
1607 elif csprng_backend in ['auto', 'openssl'] and openssl.found()
1608   libgit_c_args += '-DHAVE_OPENSSL_CSPRNG'
1609   csprng_backend = 'openssl'
1610 elif csprng_backend in ['auto', 'urandom']
1611   csprng_backend = 'urandom'
1612 else
1613   error('Unsupported CSPRNG backend: ' + csprng_backend)
1614 endif
1616 git_exec_path = 'libexec/git-core'
1617 libexec = get_option('libexecdir')
1618 if libexec != 'libexec' and libexec != '.'
1619   git_exec_path = libexec
1620 endif
1622 if get_option('runtime_prefix')
1623   libgit_c_args += '-DRUNTIME_PREFIX'
1624   build_options_config.set('RUNTIME_PREFIX', 'true')
1626   if git_exec_path.startswith('/')
1627     error('runtime_prefix requires a relative libexecdir not:', libexec)
1628   endif
1630   if compiler.has_header('mach-o/dyld.h')
1631     libgit_c_args += '-DHAVE_NS_GET_EXECUTABLE_PATH'
1632   endif
1634   if has_bsd_sysctl and compiler.compiles('''
1635     #include <sys/sysctl.h>
1637     void func(void)
1638     {
1639       KERN_PROC_PATHNAME; KERN_PROC;
1640     }
1641   ''', name: 'BSD KERN_PROC_PATHNAME')
1642     libgit_c_args += '-DHAVE_NS_GET_EXECUTABLE_PATH'
1643   endif
1645   if host_machine.system() == 'linux'
1646     libgit_c_args += '-DPROCFS_EXECUTABLE_PATH="/proc/self/exe' + '"'
1647   elif host_machine.system() == 'openbsd'
1648     libgit_c_args += '-DPROCFS_EXECUTABLE_PATH="' + '/proc/curproc/file' + '"'
1649   elif host_machine.system() == 'netbsd'
1650     libgit_c_args += '-DPROCFS_EXECUTABLE_PATH="' + '/proc/curproc/exe' + '"'
1651   endif
1653   if host_machine.system() == 'windows' and compiler.compiles('''
1654     #include <stdlib.h>
1656     void func(void)
1657     {
1658       _wpgmptr;
1659     }
1660   ''', name: 'Win32 _wpgmptr')
1661     libgit_c_args += '-DHAVE_WPGMPTR'
1662   endif
1663 else
1664   build_options_config.set('RUNTIME_PREFIX', 'false')
1665 endif
1666 libgit_c_args += '-DGIT_EXEC_PATH="' + git_exec_path + '"'
1668 git_version_file = custom_target(
1669   command: [
1670     shell,
1671     meson.current_source_dir() / 'GIT-VERSION-GEN',
1672     meson.current_source_dir(),
1673     '@INPUT@',
1674     '@OUTPUT@',
1675   ],
1676   input: meson.current_source_dir() / 'GIT-VERSION-FILE.in',
1677   output: 'GIT-VERSION-FILE',
1678   env: version_gen_environment,
1679   build_always_stale: true,
1682 version_def_h = custom_target(
1683   command: [
1684     shell,
1685     meson.current_source_dir() / 'GIT-VERSION-GEN',
1686     meson.current_source_dir(),
1687     '@INPUT@',
1688     '@OUTPUT@',
1689   ],
1690   input: meson.current_source_dir() / 'version-def.h.in',
1691   output: 'version-def.h',
1692   # Depend on GIT-VERSION-FILE so that we don't always try to rebuild this
1693   # target for the same commit.
1694   depends: [git_version_file],
1695   env: version_gen_environment,
1697 libgit_sources += version_def_h
1699 libgit = declare_dependency(
1700   link_with: static_library('git',
1701     sources: libgit_sources,
1702     c_args: libgit_c_args + [
1703       '-DGIT_VERSION_H="' + version_def_h.full_path() + '"',
1704     ],
1705     dependencies: libgit_dependencies,
1706     include_directories: libgit_include_directories,
1707   ),
1708   compile_args: libgit_c_args,
1709   dependencies: libgit_dependencies,
1710   include_directories: libgit_include_directories,
1713 common_main_sources = ['common-main.c']
1714 common_main_link_args = [ ]
1715 if host_machine.system() == 'windows'
1716   git_rc = custom_target(
1717     command: [
1718       shell,
1719       meson.current_source_dir() / 'GIT-VERSION-GEN',
1720       meson.current_source_dir(),
1721       '@INPUT@',
1722       '@OUTPUT@',
1723     ],
1724     input: meson.current_source_dir() / 'git.rc.in',
1725     output: 'git.rc',
1726     depends: [git_version_file],
1727     env: version_gen_environment,
1728   )
1730   common_main_sources += import('windows').compile_resources(git_rc,
1731     include_directories: [meson.current_source_dir()],
1732   )
1733   if compiler.get_argument_syntax() == 'gcc'
1734     common_main_link_args += [
1735       '-municode',
1736       '-Wl,-nxcompat',
1737       '-Wl,-dynamicbase',
1738       '-Wl,-pic-executable,-e,mainCRTStartup',
1739     ]
1740   elif compiler.get_argument_syntax() == 'msvc'
1741     common_main_link_args += [
1742       '/ENTRY:wmainCRTStartup',
1743       'invalidcontinue.obj',
1744     ]
1745   else
1746     error('Unsupported compiler ' + compiler.get_id())
1747   endif
1748 endif
1750 libgit_commonmain = declare_dependency(
1751   link_with: static_library('common-main',
1752     sources: common_main_sources,
1753     dependencies: [ libgit ],
1754   ),
1755   link_args: common_main_link_args,
1756   dependencies: [ libgit ],
1759 bin_wrappers = [ ]
1760 test_dependencies = [ ]
1762 git_builtin = executable('git',
1763   sources: builtin_sources + 'git.c',
1764   dependencies: [libgit_commonmain],
1765   install: true,
1766   install_dir: git_exec_path,
1768 bin_wrappers += git_builtin
1770 test_dependencies += executable('git-daemon',
1771   sources: 'daemon.c',
1772   dependencies: [libgit_commonmain],
1773   install: true,
1774   install_dir: git_exec_path,
1777 test_dependencies += executable('git-sh-i18n--envsubst',
1778   sources: 'sh-i18n--envsubst.c',
1779   dependencies: [libgit_commonmain],
1780   install: true,
1781   install_dir: git_exec_path,
1784 bin_wrappers += executable('git-shell',
1785   sources: 'shell.c',
1786   dependencies: [libgit_commonmain],
1787   install: true,
1788   install_dir: git_exec_path,
1791 test_dependencies += executable('git-http-backend',
1792   sources: 'http-backend.c',
1793   dependencies: [libgit_commonmain],
1794   install: true,
1795   install_dir: git_exec_path,
1798 bin_wrappers += executable('scalar',
1799   sources: 'scalar.c',
1800   dependencies: [libgit_commonmain],
1801   install: true,
1802   install_dir: git_exec_path,
1805 if curl.found()
1806   libgit_curl = declare_dependency(
1807     sources: [
1808       'http.c',
1809       'http-walker.c',
1810     ],
1811     dependencies: [libgit_commonmain, curl],
1812   )
1814   test_dependencies += executable('git-remote-http',
1815     sources: 'remote-curl.c',
1816     dependencies: [libgit_curl],
1817     install: true,
1818     install_dir: git_exec_path,
1819   )
1821   test_dependencies += executable('git-http-fetch',
1822     sources: 'http-fetch.c',
1823     dependencies: [libgit_curl],
1824     install: true,
1825     install_dir: git_exec_path,
1826   )
1828   if expat.found()
1829     test_dependencies += executable('git-http-push',
1830       sources: 'http-push.c',
1831       dependencies: [libgit_curl],
1832       install: true,
1833       install_dir: git_exec_path,
1834     )
1835   endif
1837   foreach alias : [ 'git-remote-https', 'git-remote-ftp', 'git-remote-ftps' ]
1838     test_dependencies += executable(alias,
1839       sources: 'remote-curl.c',
1840       dependencies: [libgit_curl],
1841     )
1843     install_symlink(alias + executable_suffix,
1844       install_dir: git_exec_path,
1845       pointing_to: 'git-remote-http',
1846     )
1847   endforeach
1848 endif
1850 test_dependencies += executable('git-imap-send',
1851   sources: 'imap-send.c',
1852   dependencies: [ use_curl_for_imap_send ? libgit_curl : libgit_commonmain ],
1853   install: true,
1854   install_dir: git_exec_path,
1857 foreach alias : [ 'git-receive-pack', 'git-upload-archive', 'git-upload-pack' ]
1858   bin_wrappers += executable(alias,
1859     objects: git_builtin.extract_all_objects(recursive: false),
1860     dependencies: [libgit_commonmain],
1861   )
1863   install_symlink(alias + executable_suffix,
1864     install_dir: git_exec_path,
1865     pointing_to: 'git',
1866   )
1867 endforeach
1869 foreach symlink : [
1870   'git',
1871   'git-receive-pack',
1872   'git-shell',
1873   'git-upload-archive',
1874   'git-upload-pack',
1875   'scalar',
1877   if meson.version().version_compare('>=1.3.0')
1878     pointing_to = fs.relative_to(git_exec_path / symlink, get_option('bindir'))
1879   else
1880     pointing_to = '..' / git_exec_path / symlink
1881   endif
1883   install_symlink(symlink,
1884     install_dir: get_option('bindir'),
1885     pointing_to: pointing_to,
1886   )
1887 endforeach
1889 scripts_sh = [
1890   'git-difftool--helper.sh',
1891   'git-filter-branch.sh',
1892   'git-merge-octopus.sh',
1893   'git-merge-one-file.sh',
1894   'git-merge-resolve.sh',
1895   'git-mergetool--lib.sh',
1896   'git-mergetool.sh',
1897   'git-quiltimport.sh',
1898   'git-request-pull.sh',
1899   'git-sh-i18n.sh',
1900   'git-sh-setup.sh',
1901   'git-submodule.sh',
1902   'git-web--browse.sh',
1904 if perl_features_enabled
1905   scripts_sh += 'git-instaweb.sh'
1906 endif
1908 foreach script : scripts_sh
1909   test_dependencies += custom_target(
1910     input: script,
1911     output: fs.stem(script),
1912     command: [
1913       shell,
1914       meson.project_source_root() / 'generate-script.sh',
1915       '@INPUT@',
1916       '@OUTPUT@',
1917       meson.project_build_root() / 'GIT-BUILD-OPTIONS',
1918     ],
1919     install: true,
1920     install_dir: git_exec_path,
1921   )
1922 endforeach
1924 if perl_features_enabled
1925   scripts_perl = [
1926     'git-archimport.perl',
1927     'git-cvsexportcommit.perl',
1928     'git-cvsimport.perl',
1929     'git-cvsserver.perl',
1930     'git-send-email.perl',
1931     'git-svn.perl',
1932   ]
1934   pathsep = ':'
1935   if host_machine.system() == 'windows'
1936     pathsep = ';'
1937   endif
1939   perl_header_template = 'perl/header_templates/fixed_prefix.template.pl'
1940   if get_option('runtime_prefix')
1941     perl_header_template = 'perl/header_templates/runtime_prefix.template.pl'
1942   endif
1944   perllibdir = get_option('perllibdir')
1945   if perllibdir == ''
1946     perllibdir = get_option('datadir') / 'perl5'
1947   endif
1949   perl_header = configure_file(
1950     input: perl_header_template,
1951     output: 'GIT-PERL-HEADER',
1952     configuration: {
1953       'GITEXECDIR_REL': git_exec_path,
1954       'PERLLIBDIR_REL': perllibdir,
1955       'LOCALEDIR_REL': get_option('datadir') / 'locale',
1956       'INSTLIBDIR': perllibdir,
1957       'PATHSEP': pathsep,
1958     },
1959   )
1961   generate_perl_command = [
1962     shell,
1963     meson.project_source_root() / 'generate-perl.sh',
1964     meson.project_build_root() / 'GIT-BUILD-OPTIONS',
1965     git_version_file.full_path(),
1966     perl_header,
1967     '@INPUT@',
1968     '@OUTPUT@',
1969   ]
1971   foreach script : scripts_perl
1972     generated_script = custom_target(
1973       input: script,
1974       output: fs.stem(script),
1975       command: generate_perl_command,
1976       install: true,
1977       install_dir: git_exec_path,
1978       depends: [git_version_file],
1979     )
1980     test_dependencies += generated_script
1982     if script == 'git-cvsserver.perl'
1983       bin_wrappers += generated_script
1985       if meson.version().version_compare('>=1.3.0')
1986         pointing_to = fs.relative_to(git_exec_path / fs.stem(script), get_option('bindir'))
1987       else
1988         pointing_to = '..' / git_exec_path / fs.stem(script)
1989       endif
1991       install_symlink(fs.stem(script),
1992         install_dir: get_option('bindir'),
1993         pointing_to: pointing_to,
1994       )
1995     endif
1996   endforeach
1998   subdir('perl')
1999 endif
2001 if target_python.found()
2002   scripts_python = [
2003     'git-p4.py'
2004   ]
2006   foreach script : scripts_python
2007     generated_python = custom_target(
2008       input: script,
2009       output: fs.stem(script),
2010       command: [
2011         shell,
2012         meson.project_source_root() / 'generate-python.sh',
2013         meson.project_build_root() / 'GIT-BUILD-OPTIONS',
2014         '@INPUT@',
2015         '@OUTPUT@',
2016       ],
2017       install: true,
2018       install_dir: git_exec_path,
2019     )
2020     test_dependencies += generated_python
2021   endforeach
2022 endif
2024 mergetools = [
2025   'mergetools/araxis',
2026   'mergetools/bc',
2027   'mergetools/codecompare',
2028   'mergetools/deltawalker',
2029   'mergetools/diffmerge',
2030   'mergetools/diffuse',
2031   'mergetools/ecmerge',
2032   'mergetools/emerge',
2033   'mergetools/examdiff',
2034   'mergetools/guiffy',
2035   'mergetools/gvimdiff',
2036   'mergetools/kdiff3',
2037   'mergetools/kompare',
2038   'mergetools/meld',
2039   'mergetools/nvimdiff',
2040   'mergetools/opendiff',
2041   'mergetools/p4merge',
2042   'mergetools/smerge',
2043   'mergetools/tkdiff',
2044   'mergetools/tortoisemerge',
2045   'mergetools/vimdiff',
2046   'mergetools/vscode',
2047   'mergetools/winmerge',
2048   'mergetools/xxdiff',
2051 foreach mergetool : mergetools
2052   install_data(mergetool, install_dir: git_exec_path / 'mergetools')
2053 endforeach
2055 if intl.found()
2056   subdir('po')
2057 endif
2059 # Gitweb requires Perl, so we disable the auto-feature if Perl was not found.
2060 # We make sure further up that Perl is required in case the gitweb option is
2061 # enabled.
2062 gitweb_option = get_option('gitweb').disable_auto_if(not perl.found())
2063 if gitweb_option.allowed()
2064   subdir('gitweb')
2065   build_options_config.set('NO_GITWEB', '')
2066 else
2067   build_options_config.set('NO_GITWEB', '1')
2068 endif
2070 subdir('templates')
2072 # Everything but the bin-wrappers need to come before this target such that we
2073 # can properly set up test dependencies. The bin-wrappers themselves are set up
2074 # at configuration time, so these are fine.
2075 if get_option('tests')
2076   test_kwargs = {
2077     'timeout': 0,
2078   }
2080   # The TAP protocol was already understood by previous versions of Meson, but
2081   # it was incompatible with the `meson test --interactive` flag.
2082   if meson.version().version_compare('>=1.8.0')
2083     test_kwargs += {
2084       'protocol': 'tap',
2085     }
2086   endif
2088   subdir('t')
2089 endif
2091 if get_option('fuzzers')
2092   subdir('oss-fuzz')
2093 endif
2095 subdir('bin-wrappers')
2096 if get_option('docs') != []
2097   subdir('Documentation')
2098 endif
2100 subdir('contrib')
2102 exclude_from_check_headers = [
2103   'compat/',
2104   'unicode-width.h',
2107 if sha1_backend != 'openssl'
2108   exclude_from_check_headers += 'sha1/openssl.h'
2109 endif
2110 if sha256_backend != 'openssl'
2111   exclude_from_check_headers += 'sha256/openssl.h'
2112 endif
2113 if sha256_backend != 'nettle'
2114   exclude_from_check_headers += 'sha256/nettle.h'
2115 endif
2116 if sha256_backend != 'gcrypt'
2117   exclude_from_check_headers += 'sha256/gcrypt.h'
2118 endif
2120 if headers_to_check.length() != 0 and compiler.get_argument_syntax() == 'gcc'
2121   hco_targets = []
2122   foreach h : headers_to_check
2123     skip_header = false
2124     foreach exclude : exclude_from_check_headers
2125       if h.startswith(exclude)
2126         skip_header = true
2127         break
2128       endif
2129     endforeach
2131     if skip_header
2132       continue
2133     endif
2135     hcc = custom_target(
2136       input: h,
2137       output: h.underscorify() + 'cc',
2138       command: [
2139         shell,
2140         '-c',
2141         'echo \'#include "git-compat-util.h"\' > @OUTPUT@ && echo \'#include "' + h + '"\' >> @OUTPUT@'
2142       ]
2143     )
2145     hco = custom_target(
2146       input: hcc,
2147       output: fs.replace_suffix(h.underscorify(), '.hco'),
2148       command: [
2149         compiler.cmd_array(),
2150         libgit_c_args,
2151         '-I', meson.project_source_root(),
2152         '-I', meson.project_source_root() / 't/unit-tests',
2153         '-o', '/dev/null',
2154         '-c', '-xc',
2155         '@INPUT@'
2156       ]
2157     )
2158     hco_targets += hco
2159   endforeach
2161   # TODO: deprecate 'hdr-check' in lieu of 'check-headers' in Git 2.51+
2162   hdr_check = alias_target('hdr-check', hco_targets)
2163   alias_target('check-headers', hdr_check)
2164 endif
2166 git_clang_format = find_program('git-clang-format', required: false, native: true)
2167 if git_clang_format.found()
2168   run_target('style',
2169     command: [
2170       git_clang_format,
2171       '--style', 'file',
2172       '--diff',
2173       '--extensions', 'c,h'
2174     ]
2175   )
2176 endif
2178 foreach key, value : {
2179   'DIFF': diff.full_path(),
2180   'GIT_SOURCE_DIR': meson.project_source_root(),
2181   'GIT_TEST_CMP': diff.full_path() + ' -u',
2182   'GIT_TEST_GITPERLLIB': meson.project_build_root() / 'perl',
2183   'GIT_TEST_TEMPLATE_DIR': meson.project_build_root() / 'templates',
2184   'GIT_TEST_TEXTDOMAINDIR': meson.project_build_root() / 'po',
2185   'PAGER_ENV': get_option('pager_environment'),
2186   'PERL_PATH': target_perl.found() ? target_perl.full_path() : '',
2187   'PYTHON_PATH': target_python.found () ? target_python.full_path() : '',
2188   'SHELL_PATH': target_shell.full_path(),
2189   'TAR': tar.full_path(),
2190   'TEST_OUTPUT_DIRECTORY': test_output_directory,
2191   'TEST_SHELL_PATH': shell.full_path(),
2193   if value != '' and cygpath.found()
2194     value = run_command(cygpath, value, check: true).stdout().strip()
2195   endif
2196   build_options_config.set_quoted(key, value)
2197 endforeach
2199 configure_file(
2200   input: 'GIT-BUILD-OPTIONS.in',
2201   output: 'GIT-BUILD-OPTIONS',
2202   configuration: build_options_config,
2205 # Development environments can be used via `meson devenv -C <builddir>`. This
2206 # allows you to execute test scripts directly with the built Git version and
2207 # puts the built version of Git in your PATH.
2208 devenv = environment()
2209 devenv.set('GIT_BUILD_DIR', meson.current_build_dir())
2210 devenv.prepend('PATH', meson.current_build_dir() / 'bin-wrappers')
2211 meson.add_devenv(devenv)
2213 # Generate the 'version' file in the distribution tarball. This is used via
2214 # `meson dist -C <builddir>` to populate the source archive with the Git
2215 # version that the archive is being generated from.
2216 meson.add_dist_script(
2217   shell,
2218   '-c',
2219   '"$1" "$2" "$3" --format="@GIT_VERSION@" "$MESON_DIST_ROOT/version"',
2220   'GIT-VERSION-GEN',
2221   shell,
2222   meson.current_source_dir() / 'GIT-VERSION-GEN',
2223   meson.current_source_dir(),
2226 summary({
2227   'benchmarks': get_option('tests') and perl.found() and time.found(),
2228   'curl': curl,
2229   'expat': expat,
2230   'gettext': intl,
2231   'gitweb': gitweb_option.allowed(),
2232   'iconv': iconv,
2233   'pcre2': pcre2,
2234   'perl': perl_features_enabled,
2235   'python': target_python.found(),
2236 }, section: 'Auto-detected features', bool_yn: true)
2238 summary({
2239   'csprng': csprng_backend,
2240   'https': https_backend,
2241   'sha1': sha1_backend,
2242   'sha1_unsafe': sha1_unsafe_backend,
2243   'sha256': sha256_backend,
2244   'zlib': zlib_backend,
2245 }, section: 'Backends')
2247 summary({
2248   'perl': target_perl,
2249   'python': target_python,
2250   'shell': target_shell,
2251 }, section: 'Runtime executable paths')