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