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