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