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