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