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 elif not get_option('regex').enabled()
1411 libgit_c_args += [
1412 '-DNO_REGEX',
1413 '-DGAWK',
1414 '-DNO_MBSUPPORT',
1415 ]
1416 build_options_config.set('NO_REGEX', '1')
1417 compat_sources += 'compat/regex/regex.c'
1418 libgit_include_directories += 'compat/regex'
1419 else
1420 error('Native regex support requested but not found')
1421 endif
1422
1423 # setitimer and friends are provided by compat/mingw.c.
1424 if host_machine.system() != 'windows'
1425 if not compiler.compiles('''
1426 #include <sys/time.h>
1427 void func(void)
1428 {
1429 struct itimerval value;
1430 }
1431 ''', name: 'struct itimerval')
1432 libgit_c_args += '-DNO_STRUCT_ITIMERVAL'
1433 libgit_c_args += '-DNO_SETITIMER'
1434 elif not compiler.has_function('setitimer')
1435 libgit_c_args += '-DNO_SETITIMER'
1436 endif
1437 endif
1438
1439 if compiler.has_member('struct stat', 'st_mtimespec.tv_nsec', prefix: '#include <sys/stat.h>')
1440 libgit_c_args += '-DUSE_ST_TIMESPEC'
1441 elif not compiler.has_member('struct stat', 'st_mtim.tv_nsec', prefix: '#include <sys/stat.h>')
1442 libgit_c_args += '-DNO_NSEC'
1443 endif
1444
1445 if not compiler.has_member('struct stat', 'st_blocks', prefix: '#include <sys/stat.h>')
1446 libgit_c_args += '-DNO_ST_BLOCKS_IN_STRUCT_STAT'
1447 endif
1448
1449 if not compiler.has_member('struct dirent', 'd_type', prefix: '#include <dirent.h>')
1450 libgit_c_args += '-DNO_D_TYPE_IN_DIRENT'
1451 endif
1452
1453 if not compiler.has_member('struct passwd', 'pw_gecos', prefix: '#include <pwd.h>')
1454 libgit_c_args += '-DNO_GECOS_IN_PWENT'
1455 endif
1456
1457 checkfuncs = {
1458 'strcasestr' : ['strcasestr.c'],
1459 'memmem' : ['memmem.c'],
1460 'strlcpy' : ['strlcpy.c'],
1461 'strtoull' : [],
1462 'setenv' : ['setenv.c'],
1463 'mkdtemp' : [],
1464 'initgroups' : [],
1465 'strtoumax' : ['strtoumax.c', 'strtoimax.c'],
1466 'pread' : ['pread.c'],
1467 'writev' : ['writev.c'],
1468 }
1469
1470 if host_machine.system() == 'windows'
1471 libgit_c_args += '-DUSE_WIN32_MMAP'
1472 else
1473 checkfuncs += {
1474 # provided by compat/mingw.c.
1475 'unsetenv' : ['unsetenv.c'],
1476 # provided by compat/mingw.c.
1477 'getpagesize' : [],
1478 }
1479
1480 if get_option('b_sanitize').contains('address') or get_option('b_sanitize').contains('leak')
1481 libgit_c_args += '-DNO_MMAP'
1482 compat_sources += 'compat/mmap.c'
1483 else
1484 checkfuncs += { 'mmap': ['mmap.c'] }
1485 endif
1486 endif
1487
1488 foreach func, impls : checkfuncs
1489 if not compiler.has_function(func)
1490 libgit_c_args += '-DNO_' + func.to_upper()
1491 foreach impl : impls
1492 compat_sources += 'compat/' + impl
1493 endforeach
1494 endif
1495 endforeach
1496
1497 if compiler.has_function('sync_file_range')
1498 libgit_c_args += '-DHAVE_SYNC_FILE_RANGE'
1499 endif
1500
1501 if not compiler.has_function('strdup')
1502 libgit_c_args += '-DOVERRIDE_STRDUP'
1503 compat_sources += 'compat/strdup.c'
1504 endif
1505
1506 if not compiler.has_function('qsort')
1507 libgit_c_args += '-DINTERNAL_QSORT'
1508 endif
1509 compat_sources += 'compat/qsort_s.c'
1510
1511 if compiler.has_function('getdelim')
1512 libgit_c_args += '-DHAVE_GETDELIM'
1513 endif
1514
1515
1516 if compiler.has_function('clock_gettime')
1517 libgit_c_args += '-DHAVE_CLOCK_GETTIME'
1518 endif
1519
1520 if compiler.compiles('''
1521 #include <time.h>
1522
1523 void func(void)
1524 {
1525 clockid_t id = CLOCK_MONOTONIC;
1526 }
1527 ''', name: 'monotonic clock')
1528 libgit_c_args += '-DHAVE_CLOCK_MONOTONIC'
1529 endif
1530
1531 has_bsd_sysctl = false
1532 if compiler.has_header('sys/sysctl.h')
1533 if compiler.compiles('''
1534 #include <stddef.h>
1535 #include <sys/sysctl.h>
1536
1537 void func(void)
1538 {
1539 int val, mib[2] = { 0 };
1540 size_t len = sizeof(val);
1541 sysctl(mib, 2, &val, &len, NULL, 0);
1542 }
1543 ''', name: 'BSD sysctl')
1544 libgit_c_args += '-DHAVE_BSD_SYSCTL'
1545 has_bsd_sysctl = true
1546 endif
1547 endif
1548
1549 if not has_bsd_sysctl
1550 if compiler.has_member('struct sysinfo', 'totalram', prefix: '#include <sys/sysinfo.h>')
1551 libgit_c_args += '-DHAVE_SYSINFO'
1552 endif
1553 endif
1554
1555 if meson.can_run_host_binaries() and compiler.run('''
1556 #include <stdio.h>
1557
1558 int main(int argc, const char **argv)
1559 {
1560 FILE *f = fopen(".", "r");
1561 return f ? 0 : 1;
1562 }
1563 ''', name: 'fread reads directories').returncode() == 0
1564 libgit_c_args += '-DFREAD_READS_DIRECTORIES'
1565 compat_sources += 'compat/fopen.c'
1566 endif
1567
1568 if not meson.is_cross_build() and fs.exists('/dev/tty')
1569 libgit_c_args += '-DHAVE_DEV_TTY'
1570 endif
1571
1572 csprng_backend = get_option('csprng_backend')
1573 https_backend = get_option('https_backend')
1574 sha1_backend = get_option('sha1_backend')
1575 sha1_unsafe_backend = get_option('sha1_unsafe_backend')
1576 sha256_backend = get_option('sha256_backend')
1577
1578 security_framework = dependency('Security', required: 'CommonCrypto' in [https_backend, sha1_backend, sha1_unsafe_backend])
1579 core_foundation_framework = dependency('CoreFoundation', required: security_framework.found())
1580 if https_backend == 'auto' and security_framework.found()
1581 https_backend = 'CommonCrypto'
1582 endif
1583
1584 openssl_required = 'openssl' in [csprng_backend, https_backend, sha1_backend, sha1_unsafe_backend, sha256_backend]
1585 openssl = dependency('openssl',
1586 required: openssl_required,
1587 allow_fallback: openssl_required or https_backend == 'auto',
1588 default_options: ['default_library=static'],
1589 )
1590 if https_backend == 'auto' and openssl.found()
1591 https_backend = 'openssl'
1592 endif
1593
1594 if https_backend == 'CommonCrypto'
1595 libgit_dependencies += security_framework
1596 libgit_dependencies += core_foundation_framework
1597 libgit_c_args += '-DAPPLE_COMMON_CRYPTO'
1598 elif https_backend == 'openssl'
1599 libgit_dependencies += openssl
1600 else
1601 # We either couldn't find any dependencies with 'auto' or the user requested
1602 # 'none'. Both cases are benign.
1603 https_backend = 'none'
1604 endif
1605
1606 if https_backend != 'openssl'
1607 libgit_c_args += '-DNO_OPENSSL'
1608 endif
1609
1610 if sha1_backend == 'sha1dc'
1611 libgit_c_args += '-DSHA1_DC'
1612 libgit_c_args += '-DSHA1DC_NO_STANDARD_INCLUDES=1'
1613 libgit_c_args += '-DSHA1DC_INIT_SAFE_HASH_DEFAULT=0'
1614 libgit_c_args += '-DSHA1DC_CUSTOM_INCLUDE_SHA1_C="git-compat-util.h"'
1615 libgit_c_args += '-DSHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C="git-compat-util.h"'
1616
1617 libgit_sources += [
1618 'sha1dc_git.c',
1619 'sha1dc/sha1.c',
1620 'sha1dc/ubc_check.c',
1621 ]
1622 endif
1623 if sha1_backend == 'CommonCrypto' or sha1_unsafe_backend == 'CommonCrypto'
1624 if sha1_backend == 'CommonCrypto'
1625 libgit_c_args += '-DSHA1_APPLE'
1626 endif
1627 if sha1_unsafe_backend == 'CommonCrypto'
1628 libgit_c_args += '-DSHA1_APPLE_UNSAFE'
1629 endif
1630
1631 libgit_c_args += '-DCOMMON_DIGEST_FOR_OPENSSL'
1632 # Apple CommonCrypto requires chunking
1633 libgit_c_args += '-DSHA1_MAX_BLOCK_SIZE=1024L*1024L*1024L'
1634 endif
1635 if sha1_backend == 'openssl' or sha1_unsafe_backend == 'openssl'
1636 if sha1_backend == 'openssl'
1637 libgit_c_args += '-DSHA1_OPENSSL'
1638 endif
1639 if sha1_unsafe_backend == 'openssl'
1640 libgit_c_args += '-DSHA1_OPENSSL_UNSAFE'
1641 endif
1642
1643 libgit_dependencies += openssl
1644 endif
1645 if sha1_backend == 'block' or sha1_unsafe_backend == 'block'
1646 if sha1_backend == 'block'
1647 libgit_c_args += '-DSHA1_BLK'
1648 endif
1649 if sha1_unsafe_backend == 'block'
1650 libgit_c_args += '-DSHA1_BLK_UNSAFE'
1651 endif
1652
1653 libgit_sources += 'block-sha1/sha1.c'
1654 endif
1655
1656 if sha256_backend == 'openssl'
1657 libgit_c_args += '-DSHA256_OPENSSL'
1658 libgit_dependencies += openssl
1659 elif sha256_backend == 'nettle'
1660 nettle = dependency('nettle')
1661 libgit_dependencies += nettle
1662 libgit_c_args += '-DSHA256_NETTLE'
1663 elif sha256_backend == 'gcrypt'
1664 gcrypt = dependency('gcrypt')
1665 libgit_dependencies += gcrypt
1666 libgit_c_args += '-DSHA256_GCRYPT'
1667 elif sha256_backend == 'block'
1668 libgit_c_args += '-DSHA256_BLK'
1669 libgit_sources += 'sha256/block/sha256.c'
1670 else
1671 error('Unhandled SHA256 backend ' + sha256_backend)
1672 endif
1673
1674 # Backends are ordered to reflect our preference for more secure and faster
1675 # ones over the ones that are less so.
1676 if csprng_backend in ['auto', 'arc4random'] and compiler.has_header_symbol('stdlib.h', 'arc4random_buf', required: csprng_backend == 'arc4random')
1677 libgit_c_args += '-DHAVE_ARC4RANDOM'
1678 csprng_backend = 'arc4random'
1679 elif csprng_backend in ['auto', 'arc4random_bsd'] and compiler.has_header_symbol('bsd/stdlib.h', 'arc4random_buf', required: csprng_backend == 'arc4random_bsd')
1680 libgit_c_args += '-DHAVE_ARC4RANDOM_BSD'
1681 csprng_backend = 'arc4random_bsd'
1682 elif csprng_backend in ['auto', 'getrandom'] and compiler.has_header_symbol('sys/random.h', 'getrandom', required: csprng_backend == 'getrandom')
1683 libgit_c_args += '-DHAVE_GETRANDOM'
1684 csprng_backend = 'getrandom'
1685 elif csprng_backend in ['auto', 'getentropy'] and compiler.has_header_symbol('unistd.h', 'getentropy', required: csprng_backend == 'getentropy')
1686 libgit_c_args += '-DHAVE_GETENTROPY'
1687 csprng_backend = 'getentropy'
1688 elif csprng_backend in ['auto', 'rtlgenrandom'] and compiler.has_header_symbol('ntsecapi.h', 'RtlGenRandom', prefix: '#include <windows.h>', required: csprng_backend == 'rtlgenrandom')
1689 libgit_c_args += '-DHAVE_RTLGENRANDOM'
1690 csprng_backend = 'rtlgenrandom'
1691 elif csprng_backend in ['auto', 'openssl'] and openssl.found()
1692 libgit_c_args += '-DHAVE_OPENSSL_CSPRNG'
1693 csprng_backend = 'openssl'
1694 elif csprng_backend in ['auto', 'urandom']
1695 csprng_backend = 'urandom'
1696 else
1697 error('Unsupported CSPRNG backend: ' + csprng_backend)
1698 endif
1699
1700 git_exec_path = 'libexec/git-core'
1701 libexec = get_option('libexecdir')
1702 if libexec != 'libexec' and libexec != '.'
1703 git_exec_path = libexec
1704 endif
1705
1706 if get_option('runtime_prefix')
1707 libgit_c_args += '-DRUNTIME_PREFIX'
1708 build_options_config.set('RUNTIME_PREFIX', 'true')
1709
1710 if git_exec_path.startswith('/')
1711 error('runtime_prefix requires a relative libexecdir not:', libexec)
1712 endif
1713
1714 if compiler.has_header('mach-o/dyld.h')
1715 libgit_c_args += '-DHAVE_NS_GET_EXECUTABLE_PATH'
1716 endif
1717
1718 if has_bsd_sysctl and compiler.compiles('''
1719 #include <sys/sysctl.h>
1720
1721 void func(void)
1722 {
1723 KERN_PROC_PATHNAME; KERN_PROC;
1724 }
1725 ''', name: 'BSD KERN_PROC_PATHNAME')
1726 libgit_c_args += '-DHAVE_NS_GET_EXECUTABLE_PATH'
1727 endif
1728
1729 if host_machine.system() == 'linux'
1730 libgit_c_args += '-DPROCFS_EXECUTABLE_PATH="/proc/self/exe' + '"'
1731 elif host_machine.system() == 'openbsd'
1732 libgit_c_args += '-DPROCFS_EXECUTABLE_PATH="' + '/proc/curproc/file' + '"'
1733 elif host_machine.system() == 'netbsd'
1734 libgit_c_args += '-DPROCFS_EXECUTABLE_PATH="' + '/proc/curproc/exe' + '"'
1735 endif
1736
1737 if host_machine.system() == 'windows' and compiler.compiles('''
1738 #include <stdlib.h>
1739
1740 void func(void)
1741 {
1742 _wpgmptr;
1743 }
1744 ''', name: 'Win32 _wpgmptr')
1745 libgit_c_args += '-DHAVE_WPGMPTR'
1746 endif
1747 else
1748 build_options_config.set('RUNTIME_PREFIX', 'false')
1749 endif
1750 libgit_c_args += '-DGIT_EXEC_PATH="' + git_exec_path + '"'
1751
1752 git_version_file = custom_target(
1753 command: [
1754 shell,
1755 meson.current_source_dir() / 'GIT-VERSION-GEN',
1756 meson.current_source_dir(),
1757 '@INPUT@',
1758 '@OUTPUT@',
1759 ],
1760 input: meson.current_source_dir() / 'GIT-VERSION-FILE.in',
1761 output: 'GIT-VERSION-FILE',
1762 env: version_gen_environment,
1763 build_always_stale: true,
1764 )
1765
1766 version_def_h = custom_target(
1767 command: [
1768 shell,
1769 meson.current_source_dir() / 'GIT-VERSION-GEN',
1770 meson.current_source_dir(),
1771 '@INPUT@',
1772 '@OUTPUT@',
1773 ],
1774 input: meson.current_source_dir() / 'version-def.h.in',
1775 output: 'version-def.h',
1776 # Depend on GIT-VERSION-FILE so that we don't always try to rebuild this
1777 # target for the same commit.
1778 depends: [git_version_file],
1779 env: version_gen_environment,
1780 )
1781 libgit_sources += version_def_h
1782
1783 rust_option = get_option('rust')
1784 if rust_option.allowed()
1785 subdir('src')
1786 libgit_c_args += '-DWITH_RUST'
1787
1788 if host_machine.system() == 'windows'
1789 libgit_dependencies += compiler.find_library('userenv')
1790 endif
1791 else
1792 libgit_sources += [
1793 'varint.c',
1794 ]
1795 endif
1796
1797 libgit = declare_dependency(
1798 link_with: [
1799 static_library('compat',
1800 sources: compat_sources,
1801 c_args: libgit_c_args,
1802 dependencies: libgit_dependencies,
1803 include_directories: libgit_include_directories,
1804 ),
1805 static_library('git',
1806 sources: libgit_sources,
1807 c_args: libgit_c_args + [
1808 '-DGIT_VERSION_H="' + version_def_h.full_path() + '"',
1809 ],
1810 c_pch: 'tools/precompiled.h',
1811 dependencies: libgit_dependencies,
1812 include_directories: libgit_include_directories,
1813 ),
1814 ],
1815 compile_args: libgit_c_args,
1816 dependencies: libgit_dependencies,
1817 include_directories: libgit_include_directories,
1818 )
1819
1820 common_main_sources = ['common-main.c']
1821 common_main_link_args = [ ]
1822 if host_machine.system() == 'windows'
1823 git_rc = custom_target(
1824 command: [
1825 shell,
1826 meson.current_source_dir() / 'GIT-VERSION-GEN',
1827 meson.current_source_dir(),
1828 '@INPUT@',
1829 '@OUTPUT@',
1830 ],
1831 input: meson.current_source_dir() / 'git.rc.in',
1832 output: 'git.rc',
1833 depends: [git_version_file],
1834 env: version_gen_environment,
1835 )
1836
1837 common_main_sources += import('windows').compile_resources(git_rc,
1838 include_directories: [meson.current_source_dir()],
1839 )
1840 if compiler.get_argument_syntax() == 'gcc'
1841 common_main_link_args += [
1842 '-municode',
1843 '-Wl,-nxcompat',
1844 '-Wl,-dynamicbase',
1845 '-Wl,-pic-executable,-e,mainCRTStartup',
1846 ]
1847 elif compiler.get_argument_syntax() == 'msvc'
1848 common_main_link_args += [
1849 '/ENTRY:wmainCRTStartup',
1850 'invalidcontinue.obj',
1851 ]
1852 else
1853 error('Unsupported compiler ' + compiler.get_id())
1854 endif
1855 endif
1856
1857 libgit_commonmain = declare_dependency(
1858 link_with: static_library('common-main',
1859 sources: common_main_sources,
1860 dependencies: [ libgit ],
1861 ),
1862 link_args: common_main_link_args,
1863 dependencies: [ libgit ],
1864 )
1865
1866 bin_wrappers = [ ]
1867 test_dependencies = [ ]
1868
1869 git_builtin = executable('git',
1870 sources: builtin_sources + 'git.c',
1871 c_pch: 'tools/precompiled.h',
1872 dependencies: [libgit_commonmain],
1873 install: true,
1874 install_dir: git_exec_path,
1875 )
1876 bin_wrappers += git_builtin
1877
1878 test_dependencies += executable('git-daemon',
1879 sources: 'daemon.c',
1880 dependencies: [libgit_commonmain],
1881 install: true,
1882 install_dir: git_exec_path,
1883 )
1884
1885 test_dependencies += executable('git-sh-i18n--envsubst',
1886 sources: 'sh-i18n--envsubst.c',
1887 dependencies: [libgit_commonmain],
1888 install: true,
1889 install_dir: git_exec_path,
1890 )
1891
1892 bin_wrappers += executable('git-shell',
1893 sources: 'shell.c',
1894 dependencies: [libgit_commonmain],
1895 install: true,
1896 install_dir: git_exec_path,
1897 )
1898
1899 test_dependencies += executable('git-http-backend',
1900 sources: 'http-backend.c',
1901 dependencies: [libgit_commonmain],
1902 install: true,
1903 install_dir: git_exec_path,
1904 )
1905
1906 bin_wrappers += executable('scalar',
1907 sources: 'scalar.c',
1908 dependencies: [libgit_commonmain],
1909 install: true,
1910 install_dir: git_exec_path,
1911 )
1912
1913 if curl.found()
1914 libgit_curl = declare_dependency(
1915 sources: [
1916 'http.c',
1917 'http-walker.c',
1918 ],
1919 dependencies: [libgit_commonmain, curl],
1920 )
1921
1922 test_dependencies += executable('git-remote-http',
1923 sources: 'remote-curl.c',
1924 dependencies: [libgit_curl],
1925 install: true,
1926 install_dir: git_exec_path,
1927 )
1928
1929 test_dependencies += executable('git-http-fetch',
1930 sources: 'http-fetch.c',
1931 dependencies: [libgit_curl],
1932 install: true,
1933 install_dir: git_exec_path,
1934 )
1935
1936 if expat.found()
1937 test_dependencies += executable('git-http-push',
1938 sources: 'http-push.c',
1939 dependencies: [libgit_curl],
1940 install: true,
1941 install_dir: git_exec_path,
1942 )
1943 endif
1944
1945 foreach alias : [ 'git-remote-https', 'git-remote-ftp', 'git-remote-ftps' ]
1946 test_dependencies += executable(alias,
1947 sources: 'remote-curl.c',
1948 dependencies: [libgit_curl],
1949 )
1950
1951 install_symlink(alias + executable_suffix,
1952 install_dir: git_exec_path,
1953 pointing_to: 'git-remote-http',
1954 )
1955 endforeach
1956 endif
1957
1958 test_dependencies += executable('git-imap-send',
1959 sources: 'imap-send.c',
1960 dependencies: [ use_curl_for_imap_send ? libgit_curl : libgit_commonmain ],
1961 install: true,
1962 install_dir: git_exec_path,
1963 )
1964
1965 foreach alias : [ 'git-receive-pack', 'git-upload-archive', 'git-upload-pack' ]
1966 bin_wrappers += executable(alias,
1967 objects: git_builtin.extract_all_objects(recursive: false),
1968 dependencies: [libgit_commonmain],
1969 )
1970
1971 install_symlink(alias + executable_suffix,
1972 install_dir: git_exec_path,
1973 pointing_to: 'git',
1974 )
1975 endforeach
1976
1977 foreach symlink : [
1978 'git',
1979 'git-receive-pack',
1980 'git-shell',
1981 'git-upload-archive',
1982 'git-upload-pack',
1983 'scalar',
1984 ]
1985 if meson.version().version_compare('>=1.3.0')
1986 pointing_to = fs.relative_to(git_exec_path / symlink, get_option('bindir'))
1987 else
1988 pointing_to = '..' / git_exec_path / symlink
1989 endif
1990
1991 install_symlink(symlink,
1992 install_dir: get_option('bindir'),
1993 pointing_to: pointing_to,
1994 )
1995 endforeach
1996
1997 scripts_sh = [
1998 'git-difftool--helper.sh',
1999 'git-filter-branch.sh',
2000 'git-merge-octopus.sh',
2001 'git-merge-one-file.sh',
2002 'git-merge-resolve.sh',
2003 'git-mergetool--lib.sh',
2004 'git-mergetool.sh',
2005 'git-quiltimport.sh',
2006 'git-request-pull.sh',
2007 'git-sh-i18n.sh',
2008 'git-sh-setup.sh',
2009 'git-submodule.sh',
2010 'git-web--browse.sh',
2011 ]
2012 if perl_features_enabled
2013 scripts_sh += 'git-instaweb.sh'
2014 endif
2015
2016 foreach script : scripts_sh
2017 test_dependencies += custom_target(
2018 input: script,
2019 output: fs.stem(script),
2020 command: [
2021 shell,
2022 meson.project_source_root() / 'tools/generate-script.sh',
2023 '@INPUT@',
2024 '@OUTPUT@',
2025 meson.project_build_root() / 'GIT-BUILD-OPTIONS',
2026 ],
2027 install: true,
2028 install_dir: git_exec_path,
2029 )
2030 endforeach
2031
2032 if perl_features_enabled
2033 scripts_perl = [
2034 'git-archimport.perl',
2035 'git-cvsexportcommit.perl',
2036 'git-cvsimport.perl',
2037 'git-cvsserver.perl',
2038 'git-send-email.perl',
2039 'git-svn.perl',
2040 ]
2041
2042 pathsep = ':'
2043 if host_machine.system() == 'windows'
2044 pathsep = ';'
2045 endif
2046
2047 perl_header_template = 'perl/header_templates/fixed_prefix.template.pl'
2048 if get_option('runtime_prefix')
2049 perl_header_template = 'perl/header_templates/runtime_prefix.template.pl'
2050 endif
2051
2052 perllibdir = get_option('perllibdir')
2053 if perllibdir == ''
2054 perllibdir = get_option('datadir') / 'perl5'
2055 endif
2056
2057 perl_header = configure_file(
2058 input: perl_header_template,
2059 output: 'GIT-PERL-HEADER',
2060 configuration: {
2061 'GITEXECDIR_REL': git_exec_path,
2062 'PERLLIBDIR_REL': perllibdir,
2063 'LOCALEDIR_REL': get_option('datadir') / 'locale',
2064 'INSTLIBDIR': perllibdir,
2065 'PATHSEP': pathsep,
2066 },
2067 )
2068
2069 generate_perl_command = [
2070 shell,
2071 meson.project_source_root() / 'tools/generate-perl.sh',
2072 meson.project_build_root() / 'GIT-BUILD-OPTIONS',
2073 git_version_file.full_path(),
2074 perl_header,
2075 '@INPUT@',
2076 '@OUTPUT@',
2077 ]
2078
2079 foreach script : scripts_perl
2080 generated_script = custom_target(
2081 input: script,
2082 output: fs.stem(script),
2083 command: generate_perl_command,
2084 install: true,
2085 install_dir: git_exec_path,
2086 depends: [git_version_file],
2087 )
2088 test_dependencies += generated_script
2089
2090 if script == 'git-cvsserver.perl'
2091 bin_wrappers += generated_script
2092
2093 if meson.version().version_compare('>=1.3.0')
2094 pointing_to = fs.relative_to(git_exec_path / fs.stem(script), get_option('bindir'))
2095 else
2096 pointing_to = '..' / git_exec_path / fs.stem(script)
2097 endif
2098
2099 install_symlink(fs.stem(script),
2100 install_dir: get_option('bindir'),
2101 pointing_to: pointing_to,
2102 )
2103 endif
2104 endforeach
2105
2106 subdir('perl')
2107 endif
2108
2109 if target_python.found()
2110 scripts_python = [
2111 'git-p4.py'
2112 ]
2113
2114 foreach script : scripts_python
2115 generated_python = custom_target(
2116 input: script,
2117 output: fs.stem(script),
2118 command: [
2119 shell,
2120 meson.project_source_root() / 'tools/generate-python.sh',
2121 meson.project_build_root() / 'GIT-BUILD-OPTIONS',
2122 '@INPUT@',
2123 '@OUTPUT@',
2124 ],
2125 install: true,
2126 install_dir: git_exec_path,
2127 )
2128 test_dependencies += generated_python
2129 endforeach
2130 endif
2131
2132 mergetools = [
2133 'mergetools/araxis',
2134 'mergetools/bc',
2135 'mergetools/codecompare',
2136 'mergetools/deltawalker',
2137 'mergetools/diffmerge',
2138 'mergetools/diffuse',
2139 'mergetools/ecmerge',
2140 'mergetools/emerge',
2141 'mergetools/examdiff',
2142 'mergetools/guiffy',
2143 'mergetools/gvimdiff',
2144 'mergetools/kdiff3',
2145 'mergetools/kompare',
2146 'mergetools/meld',
2147 'mergetools/nvimdiff',
2148 'mergetools/opendiff',
2149 'mergetools/p4merge',
2150 'mergetools/smerge',
2151 'mergetools/tkdiff',
2152 'mergetools/tortoisemerge',
2153 'mergetools/vimdiff',
2154 'mergetools/vscode',
2155 'mergetools/winmerge',
2156 'mergetools/xxdiff',
2157 ]
2158
2159 foreach mergetool : mergetools
2160 install_data(mergetool, install_dir: git_exec_path / 'mergetools')
2161 endforeach
2162
2163 if intl.found()
2164 subdir('po')
2165 endif
2166
2167 # Gitweb requires Perl, so we disable the auto-feature if Perl was not found.
2168 # We make sure further up that Perl is required in case the gitweb option is
2169 # enabled.
2170 gitweb_option = get_option('gitweb').disable_auto_if(not perl.found())
2171 if gitweb_option.allowed()
2172 subdir('gitweb')
2173 build_options_config.set('NO_GITWEB', '')
2174 else
2175 build_options_config.set('NO_GITWEB', '1')
2176 endif
2177
2178 subdir('templates')
2179
2180 # Everything but the bin-wrappers need to come before this target such that we
2181 # can properly set up test dependencies. The bin-wrappers themselves are set up
2182 # at configuration time, so these are fine.
2183 if get_option('tests')
2184 test_kwargs = {
2185 'timeout': 0,
2186 }
2187
2188 # The TAP protocol was already understood by previous versions of Meson, but
2189 # it was incompatible with the `meson test --interactive` flag.
2190 if meson.version().version_compare('>=1.8.0')
2191 test_kwargs += {
2192 'protocol': 'tap',
2193 }
2194 endif
2195
2196 subdir('t')
2197 endif
2198
2199 if get_option('fuzzers')
2200 subdir('oss-fuzz')
2201 endif
2202
2203 subdir('bin-wrappers')
2204 if get_option('docs') != []
2205 doc_targets = []
2206 subdir('Documentation')
2207 else
2208 docs_backend = 'none'
2209 endif
2210
2211 subdir('contrib')
2212 subdir('tools')
2213
2214 # Note that the target is intentionally configured after including the
2215 # 'contrib' directory, as some tool there also have their own manpages.
2216 if get_option('docs') != []
2217 alias_target('docs', doc_targets)
2218 endif
2219
2220 exclude_from_check_headers = [
2221 'compat/',
2222 'unicode-width.h',
2223 ]
2224
2225 if sha1_backend != 'openssl'
2226 exclude_from_check_headers += 'sha1/openssl.h'
2227 endif
2228 if sha256_backend != 'openssl'
2229 exclude_from_check_headers += 'sha256/openssl.h'
2230 endif
2231 if sha256_backend != 'nettle'
2232 exclude_from_check_headers += 'sha256/nettle.h'
2233 endif
2234 if sha256_backend != 'gcrypt'
2235 exclude_from_check_headers += 'sha256/gcrypt.h'
2236 endif
2237
2238 if headers_to_check.length() != 0 and compiler.get_argument_syntax() == 'gcc'
2239 hco_targets = []
2240 foreach h : headers_to_check
2241 skip_header = false
2242 foreach exclude : exclude_from_check_headers
2243 if h.startswith(exclude)
2244 skip_header = true
2245 break
2246 endif
2247 endforeach
2248
2249 if skip_header
2250 continue
2251 endif
2252
2253 hcc = custom_target(
2254 input: h,
2255 output: h.underscorify() + 'cc',
2256 command: [
2257 shell,
2258 '-c',
2259 'echo \'#include "git-compat-util.h"\' > @OUTPUT@ && echo \'#include "' + h + '"\' >> @OUTPUT@'
2260 ]
2261 )
2262
2263 hco = custom_target(
2264 input: hcc,
2265 output: fs.replace_suffix(h.underscorify(), '.hco'),
2266 command: [
2267 compiler.cmd_array(),
2268 libgit_c_args,
2269 '-I', meson.project_source_root(),
2270 '-I', meson.project_source_root() / 't/unit-tests',
2271 '-o', '/dev/null',
2272 '-c', '-xc',
2273 '@INPUT@'
2274 ]
2275 )
2276 hco_targets += hco
2277 endforeach
2278
2279 # TODO: deprecate 'hdr-check' in lieu of 'check-headers' in Git 2.51+
2280 hdr_check = alias_target('hdr-check', hco_targets)
2281 alias_target('check-headers', hdr_check)
2282 endif
2283
2284 git_clang_format = find_program('git-clang-format', required: false, native: true)
2285 if git_clang_format.found()
2286 run_target('style',
2287 command: [
2288 git_clang_format,
2289 '--style', 'file',
2290 '--diff',
2291 '--extensions', 'c,h'
2292 ]
2293 )
2294 endif
2295
2296 foreach key, value : {
2297 'DIFF': diff.full_path(),
2298 'GIT_SOURCE_DIR': meson.project_source_root(),
2299 'GIT_TEST_CMP': diff.full_path() + ' -u',
2300 'GIT_TEST_GITPERLLIB': meson.project_build_root() / 'perl',
2301 'GIT_TEST_TEMPLATE_DIR': meson.project_build_root() / 'templates',
2302 'GIT_TEST_TEXTDOMAINDIR': meson.project_build_root() / 'po',
2303 'PAGER_ENV': get_option('pager_environment'),
2304 'PERL_PATH': target_perl.found() ? target_perl.full_path() : '',
2305 'PYTHON_PATH': target_python.found () ? target_python.full_path() : '',
2306 'SHELL_PATH': target_shell.full_path(),
2307 'TAR': tar.full_path(),
2308 'TEST_OUTPUT_DIRECTORY': test_output_directory,
2309 'TEST_SHELL_PATH': shell.full_path(),
2310 }
2311 if value != '' and cygpath.found()
2312 value = run_command(cygpath, value, check: true).stdout().strip()
2313 endif
2314 build_options_config.set_quoted(key, value)
2315 endforeach
2316
2317 configure_file(
2318 input: 'GIT-BUILD-OPTIONS.in',
2319 output: 'GIT-BUILD-OPTIONS',
2320 configuration: build_options_config,
2321 )
2322
2323 gitk_option = get_option('gitk').disable_auto_if(not wish.found())
2324 if gitk_option.allowed()
2325 subproject('gitk')
2326 endif
2327
2328 git_gui_option = get_option('git_gui').disable_auto_if(not tclsh.found() or not wish.found())
2329 if git_gui_option.allowed()
2330 subproject('git-gui')
2331 endif
2332
2333 # Development environments can be used via `meson devenv -C <builddir>`. This
2334 # allows you to execute test scripts directly with the built Git version and
2335 # puts the built version of Git in your PATH.
2336 devenv = environment()
2337 devenv.set('GIT_BUILD_DIR', meson.current_build_dir())
2338 devenv.prepend('PATH', meson.current_build_dir() / 'bin-wrappers')
2339 meson.add_devenv(devenv)
2340
2341 # Generate the 'version' file in the distribution tarball. This is used via
2342 # `meson dist -C <builddir>` to populate the source archive with the Git
2343 # version that the archive is being generated from.
2344 meson.add_dist_script(
2345 shell,
2346 '-c',
2347 '"$1" "$2" "$3" --format="@GIT_VERSION@" "$MESON_DIST_ROOT/version"',
2348 'GIT-VERSION-GEN',
2349 shell,
2350 meson.current_source_dir() / 'GIT-VERSION-GEN',
2351 meson.current_source_dir(),
2352 )
2353
2354 summary({
2355 'benchmarks': get_option('tests') and perl.found() and time.found(),
2356 'curl': curl,
2357 'expat': expat,
2358 'gettext': intl,
2359 'gitk': gitk_option.allowed(),
2360 'git-gui': git_gui_option.allowed(),
2361 'gitweb': gitweb_option.allowed(),
2362 'iconv': iconv,
2363 'pcre2': pcre2,
2364 'perl': perl_features_enabled,
2365 'python': target_python.found(),
2366 'rust': rust_option.allowed(),
2367 }, section: 'Auto-detected features', bool_yn: true)
2368
2369 summary({
2370 'csprng': csprng_backend,
2371 'docs': docs_backend,
2372 'https': https_backend,
2373 'sha1': sha1_backend,
2374 'sha1_unsafe': sha1_unsafe_backend,
2375 'sha256': sha256_backend,
2376 'zlib': zlib_backend,
2377 }, section: 'Backends')
2378
2379 summary({
2380 'perl': target_perl,
2381 'python': target_python,
2382 'shell': target_shell,
2383 }, section: 'Runtime executable paths')