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:
7 # - Out-of-tree builds.
8 # - Better integration into IDEs.
9 # - Easy-to-use autoconfiguration of available features on your system.
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.
19 # In the most trivial case, you can configure, build and install Git like this:
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.
25 # $ meson setup build/
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.
31 # 2. Compile Git. You can either use Meson, Ninja or Samurai to do this, so all
32 # of the following invocations are equivalent:
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.
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.
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.
50 # 3. Execute tests. Again, you can either use Meson, Ninja or Samurai to do this:
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
61 # # Execute the t0000-basic integration test and t-reftable-stack unit test.
62 # $ meson test t0000-basic t-reftable-stack
64 # # Execute all reftable unit tests.
65 # $ meson test t-reftable-*
67 # # Execute all tests and stop with the first failure.
68 # $ meson test --maxfail 1
70 # # Execute single test interactively such that features like `debug ()` work.
71 # $ meson test -i --test-args='-ix' t1400-update-ref
73 # # Execute all benchmarks.
74 # $ meson test -i --benchmark
76 # # Execute single benchmark.
77 # $ meson test -i --benchmark p0000-*
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`.
83 # 4. Install the Git distribution. Again, this can be done via Meson, Ninja or
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.
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.
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:
107 # - Built-in options provided by Meson.
109 # - Options defined by the project in the "meson_options.txt" file.
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
115 # Options can be configured either when setting up the build directory or can
116 # be changed in preexisting build directories:
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
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
127 # # Set up a new build directory with 'address' and 'undefined' sanitizers
129 # $ CC=clang meson setup -Db_sanitize=address,undefined build
131 # # Disable tests in a preexisting build directory.
132 # $ meson configure -Dtests=false
134 # # Disable features based on Python
135 # $ meson configure -Dpython=disabled
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.
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:
154 # gettext = 'disabled'
155 # default_editor = 'vim'
159 # b_sanitize = 'address,undefined'
161 # These machine files can be passed to `meson setup` via the `--native-file`
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:
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'
182 # cpu_family = 'x86_64'
186 # These machine files can be passed to `meson setup` via the `--cross-file`
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
195 # Subproject wrappers
196 # ===================
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.
205 # The use of subproject wrappers can be disabled by executing `meson setup`
206 # with the `--wrap-mode nofallback` option.
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@',
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') ? ['c_std=gnu99,c11'] : ['c_std=gnu99'],
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' ]
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 time = find_program('time', dirs: program_path, required: get_option('benchmarks'))
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`.
248 target_shell = find_program('/bin/sh', 'sh', dirs: program_path, native: false)
250 # Sanity-check that programs required for the build exist.
251 foreach tool : ['cat', 'cut', 'grep', 'sort', 'tr', 'uname']
252 find_program(tool, dirs: program_path, native: true)
255 script_environment = environment()
256 foreach path : program_path
257 script_environment.prepend('PATH', path)
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.
264 version_gen_environment = script_environment
265 version_gen_environment.set('GIT_BUILT_FROM_COMMIT', get_option('built_from_commit'))
266 version_gen_environment.set('GIT_DATE', get_option('build_date'))
267 version_gen_environment.set('GIT_USER_AGENT', get_option('user_agent'))
268 version_gen_environment.set('GIT_VERSION', get_option('version'))
270 compiler = meson.get_compiler('c')
310 'compiler-tricks/not-constant.c',
331 'diffcore-pickaxe.c',
340 'ewah/ewah_bitmap.c',
344 'fetch-negotiator.c',
350 'fsmonitor-settings.c',
369 'linear-assignment.c',
370 'list-objects-filter-options.c',
371 'list-objects-filter.c',
384 'merge-ort-wrappers.c',
389 'negotiator/default.c',
391 'negotiator/skipping.c',
396 'object-file-convert.c',
405 'pack-bitmap-write.c',
414 'parallel-checkout.c',
416 'parse-options-cb.c',
438 'rebase-interactive.c',
445 'refs/files-backend.c',
446 'refs/reftable-backend.c',
448 'refs/packed-backend.c',
454 'reftable/blocksource.c',
491 'submodule-config.c',
501 'trace2/tr2_cmd_name.c',
505 'trace2/tr2_sysenv.c',
507 'trace2/tr2_tgt_event.c',
508 'trace2/tr2_tgt_normal.c',
509 'trace2/tr2_tgt_perf.c',
513 'transport-helper.c',
538 'xdiff/xhistogram.c',
545 libgit_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,
555 'builtin/annotate.c',
558 'builtin/backfill.c',
562 'builtin/bugreport.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',
575 'builtin/commit-graph.c',
576 'builtin/commit-tree.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',
591 'builtin/difftool.c',
592 'builtin/fast-export.c',
593 'builtin/fast-import.c',
594 'builtin/fetch-pack.c',
596 'builtin/fmt-merge-msg.c',
597 'builtin/for-each-ref.c',
598 'builtin/for-each-repo.c',
600 'builtin/fsmonitor--daemon.c',
602 'builtin/get-tar-commit-id.c',
604 'builtin/hash-object.c',
607 'builtin/index-pack.c',
609 'builtin/interpret-trailers.c',
611 'builtin/ls-files.c',
612 'builtin/ls-remote.c',
614 'builtin/mailinfo.c',
615 'builtin/mailsplit.c',
616 'builtin/merge-base.c',
617 'builtin/merge-file.c',
618 'builtin/merge-index.c',
619 'builtin/merge-ours.c',
620 'builtin/merge-recursive.c',
621 'builtin/merge-tree.c',
625 'builtin/multi-pack-index.c',
627 'builtin/name-rev.c',
629 'builtin/pack-objects.c',
630 'builtin/pack-refs.c',
631 'builtin/patch-id.c',
632 'builtin/prune-packed.c',
636 'builtin/range-diff.c',
637 'builtin/read-tree.c',
639 'builtin/receive-pack.c',
642 'builtin/remote-ext.c',
643 'builtin/remote-fd.c',
650 'builtin/rev-list.c',
651 'builtin/rev-parse.c',
654 'builtin/send-pack.c',
655 'builtin/shortlog.c',
656 'builtin/show-branch.c',
657 'builtin/show-index.c',
658 'builtin/show-ref.c',
659 'builtin/sparse-checkout.c',
661 'builtin/stripspace.c',
662 'builtin/submodule--helper.c',
663 'builtin/symbolic-ref.c',
665 'builtin/unpack-file.c',
666 'builtin/unpack-objects.c',
667 'builtin/update-index.c',
668 'builtin/update-ref.c',
669 'builtin/update-server-info.c',
670 'builtin/upload-archive.c',
671 'builtin/upload-pack.c',
673 'builtin/verify-commit.c',
674 'builtin/verify-pack.c',
675 'builtin/verify-tag.c',
676 'builtin/worktree.c',
677 'builtin/write-tree.c',
680 third_party_excludes = [
682 ':!compat/inet_ntop.c',
683 ':!compat/inet_pton.c',
684 ':!compat/nedmalloc',
685 ':!compat/obstack.*',
688 ':!sha1collisiondetection',
690 ':!t/unit-tests/clar',
691 ':!t/t[0-9][0-9][0-9][0-9]*',
695 headers_to_check = []
696 if git.found() and fs.exists(meson.project_source_root() / '.git')
697 foreach header : run_command(git, '-C', meson.project_source_root(), 'ls-files', '--deduplicate', '*.h', third_party_excludes, check: true).stdout().split()
698 headers_to_check += header
702 if not get_option('breaking_changes')
703 builtin_sources += 'builtin/pack-redundant.c'
706 builtin_sources += custom_target(
707 output: 'config-list.h',
710 meson.current_source_dir() + '/generate-configlist.sh',
711 meson.current_source_dir(),
714 env: script_environment,
717 builtin_sources += custom_target(
718 input: 'Documentation/githooks.adoc',
719 output: 'hook-list.h',
722 meson.current_source_dir() + '/generate-hooklist.sh',
723 meson.current_source_dir(),
726 env: script_environment,
729 # This contains the variables for GIT-BUILD-OPTIONS, which we use to propagate
730 # build options to our tests.
731 build_options_config = configuration_data()
732 build_options_config.set('GIT_INTEROP_MAKE_OPTS', '')
733 build_options_config.set_quoted('GIT_PERF_LARGE_REPO', get_option('benchmark_large_repo'))
734 build_options_config.set('GIT_PERF_MAKE_COMMAND', '')
735 build_options_config.set('GIT_PERF_MAKE_OPTS', '')
736 build_options_config.set_quoted('GIT_PERF_REPEAT_COUNT', get_option('benchmark_repeat_count').to_string())
737 build_options_config.set_quoted('GIT_PERF_REPO', get_option('benchmark_repo'))
738 build_options_config.set('GIT_TEST_CMP_USE_COPIED_CONTEXT', '')
739 build_options_config.set('GIT_TEST_INDEX_VERSION', '')
740 build_options_config.set('GIT_TEST_OPTS', '')
741 build_options_config.set('GIT_TEST_PERL_FATAL_WARNINGS', '')
742 build_options_config.set_quoted('GIT_TEST_UTF8_LOCALE', get_option('test_utf8_locale'))
743 build_options_config.set_quoted('LOCALEDIR', fs.as_posix(get_option('prefix') / get_option('localedir')))
744 build_options_config.set_quoted('GITWEBDIR', fs.as_posix(get_option('prefix') / get_option('datadir') / 'gitweb'))
746 if get_option('sane_tool_path').length() != 0
747 sane_tool_path = (host_machine.system() == 'windows' ? ';' : ':').join(get_option('sane_tool_path'))
748 build_options_config.set_quoted('BROKEN_PATH_FIX', 's|^\# @BROKEN_PATH_FIX@$|git_broken_path_fix "' + sane_tool_path + '"|')
750 build_options_config.set_quoted('BROKEN_PATH_FIX', '/^\# @BROKEN_PATH_FIX@$/d')
753 test_output_directory = get_option('test_output_directory')
754 if test_output_directory == ''
755 test_output_directory = meson.project_build_root() / 'test-output'
758 # These variables are used for building libgit.a.
760 '-DBINDIR="' + get_option('bindir') + '"',
761 '-DDEFAULT_GIT_TEMPLATE_DIR="' + get_option('datadir') / 'git-core/templates' + '"',
762 '-DFALLBACK_RUNTIME_PREFIX="' + get_option('prefix') + '"',
763 '-DGIT_HOST_CPU="' + host_machine.cpu_family() + '"',
764 '-DGIT_HTML_PATH="' + get_option('datadir') / 'doc/git-doc"',
765 '-DGIT_INFO_PATH="' + get_option('infodir') + '"',
766 '-DGIT_LOCALE_PATH="' + get_option('localedir') + '"',
767 '-DGIT_MAN_PATH="' + get_option('mandir') + '"',
768 '-DPAGER_ENV="' + get_option('pager_environment') + '"',
769 '-DSHELL_PATH="' + fs.as_posix(target_shell.full_path()) + '"',
772 system_attributes = get_option('gitattributes')
773 if system_attributes != ''
774 libgit_c_args += '-DETC_GITATTRIBUTES="' + system_attributes + '"'
776 libgit_c_args += '-DETC_GITATTRIBUTES="' + get_option('sysconfdir') / 'gitattributes"'
779 system_config = get_option('gitconfig')
780 if system_config != ''
781 libgit_c_args += '-DETC_GITCONFIG="' + system_config + '"'
783 libgit_c_args += '-DETC_GITCONFIG="' + get_option('sysconfdir') / 'gitconfig"'
786 editor_opt = get_option('default_editor')
787 if editor_opt != '' and editor_opt != 'vi'
788 libgit_c_args += '-DDEFAULT_EDITOR="' + editor_opt + '"'
791 pager_opt = get_option('default_pager')
792 if pager_opt != '' and pager_opt != 'less'
793 libgit_c_args += '-DDEFAULT_PAGER="' + pager_opt + '"'
796 help_format_opt = get_option('default_help_format')
797 if help_format_opt == 'platform'
798 if host_machine.system() == 'windows'
799 help_format_opt = 'html'
801 help_format_opt = 'man'
804 if help_format_opt != 'man'
805 libgit_c_args += '-DDEFAULT_HELP_FORMAT="' + help_format_opt + '"'
808 libgit_include_directories = [ '.' ]
809 libgit_dependencies = [ ]
811 # Treat any warning level above 1 the same as we treat DEVELOPER=1 in our
813 if get_option('warning_level') in ['2','3', 'everything'] and compiler.get_argument_syntax() == 'gcc'
816 '-Wdeclaration-after-statement',
818 '-Wold-style-definition',
821 '-Wstrict-prototypes',
822 '-Wunreachable-code',
827 '-Wtautological-constant-out-of-range-compare',
828 # If a function is public, there should be a prototype and the right
829 # header file should be included. If not, it should be static.
830 '-Wmissing-prototypes',
831 # These are disabled because we have these all over the place.
833 '-Wno-missing-field-initializers',
835 if compiler.has_argument(cflag)
836 libgit_c_args += cflag
841 if get_option('breaking_changes')
842 build_options_config.set('WITH_BREAKING_CHANGES', 'YesPlease')
843 libgit_c_args += '-DWITH_BREAKING_CHANGES'
845 build_options_config.set('WITH_BREAKING_CHANGES', '')
848 if get_option('b_sanitize').contains('address')
849 build_options_config.set('SANITIZE_ADDRESS', 'YesCompiledWithIt')
851 build_options_config.set('SANITIZE_ADDRESS', '')
853 if get_option('b_sanitize').contains('leak')
854 build_options_config.set('SANITIZE_LEAK', 'YesCompiledWithIt')
856 build_options_config.set('SANITIZE_LEAK', '')
858 if get_option('b_sanitize').contains('undefined')
859 libgit_c_args += '-DSHA1DC_FORCE_ALIGNED_ACCESS'
862 executable_suffix = ''
863 if host_machine.system() == 'cygwin' or host_machine.system() == 'windows'
864 executable_suffix = '.exe'
865 libgit_c_args += '-DSTRIP_EXTENSION="' + executable_suffix + '"'
867 build_options_config.set_quoted('X', executable_suffix)
869 # Python is not used for our build system, but exclusively for git-p4.
870 # Consequently we only need to determine whether Python is available for the
872 target_python = find_program('python3', native: false, required: get_option('python'))
873 if target_python.found()
874 build_options_config.set('NO_PYTHON', '')
876 libgit_c_args += '-DNO_PYTHON'
877 build_options_config.set('NO_PYTHON', '1')
880 # Perl is used for two different things: our test harness and to provide some
881 # features. It is optional if you want to neither execute tests nor use any of
882 # these optional features.
883 perl_required = get_option('perl')
884 if get_option('benchmarks').enabled() or get_option('gitweb').enabled() or 'netrc' in get_option('credential_helpers')
888 # Note that we only set NO_PERL if the Perl features were disabled by the user.
889 # It may not be set when we have found Perl, but only use it to run tests.
891 # At the time of writing, executing `perl --version` results in a string
892 # similar to the following output:
894 # This is perl 5, version 40, subversion 0 (v5.40.0) built for x86_64-linux-thread-multi
896 # Meson picks up the "40" as version number instead of using "v5.40.0"
897 # due to the regular expression it uses. This got fixed in Meson 1.7.0,
898 # but meanwhile we have to either use `-V:version` instead of `--version`,
899 # which we can do starting with Meson 1.5.0 and newer, or we have to
900 # match against the minor version.
901 if meson.version().version_compare('>=1.5.0')
902 perl = find_program('perl', dirs: program_path, native: true, required: perl_required, version: '>=5.26.0', version_argument: '-V:version')
903 target_perl = find_program('perl', dirs: program_path, native: false, required: perl.found(), version: '>=5.26.0', version_argument: '-V:version')
905 perl = find_program('perl', dirs: program_path, native: true, required: perl_required, version: '>=26')
906 target_perl = find_program('perl', dirs: program_path, native: false, required: perl.found(), version: '>=26')
908 perl_features_enabled = perl.found() and get_option('perl').allowed()
909 if perl_features_enabled
910 build_options_config.set('NO_PERL', '')
912 if get_option('runtime_prefix')
913 build_options_config.set('PERL_LOCALEDIR', '')
915 build_options_config.set_quoted('PERL_LOCALEDIR', fs.as_posix(get_option('prefix') / get_option('localedir')))
918 if get_option('perl_cpan_fallback')
919 build_options_config.set('NO_PERL_CPAN_FALLBACKS', '')
921 build_options_config.set_quoted('NO_PERL_CPAN_FALLBACKS', 'YesPlease')
924 libgit_c_args += '-DNO_PERL'
925 build_options_config.set('NO_PERL', '1')
926 build_options_config.set('PERL_LOCALEDIR', '')
927 build_options_config.set('NO_PERL_CPAN_FALLBACKS', '')
930 zlib_backend = get_option('zlib_backend')
931 if zlib_backend in ['auto', 'zlib-ng']
932 zlib_ng = dependency('zlib-ng', required: zlib_backend == 'zlib-ng')
934 zlib_backend = 'zlib-ng'
935 libgit_c_args += '-DHAVE_ZLIB_NG'
936 libgit_dependencies += zlib_ng
939 if zlib_backend in ['auto', 'zlib']
940 zlib = dependency('zlib', default_options: ['default_library=static', 'tests=disabled'])
941 if zlib.version().version_compare('<1.2.0')
942 libgit_c_args += '-DNO_DEFLATE_BOUND'
944 zlib_backend = 'zlib'
945 libgit_dependencies += zlib
948 threads = dependency('threads', required: false)
950 libgit_dependencies += threads
951 build_options_config.set('NO_PTHREADS', '')
953 libgit_c_args += '-DNO_PTHREADS'
954 build_options_config.set('NO_PTHREADS', '1')
957 msgfmt = find_program('msgfmt', dirs: program_path, native: true, required: false)
958 gettext_option = get_option('gettext').disable_auto_if(not msgfmt.found())
959 if not msgfmt.found() and gettext_option.enabled()
960 error('Internationalization via libintl requires msgfmt')
963 if gettext_option.allowed() and host_machine.system() == 'darwin' and get_option('macos_use_homebrew_gettext')
964 if host_machine.cpu_family() == 'x86_64'
965 libintl_prefix = '/usr/local'
966 elif host_machine.cpu_family() == 'aarch64'
967 libintl_prefix = '/opt/homebrew'
969 error('Homebrew workaround not supported on current architecture')
972 intl = compiler.find_library('intl', dirs: libintl_prefix / 'lib', required: gettext_option)
974 intl = declare_dependency(
976 include_directories: libintl_prefix / 'include',
980 intl = dependency('intl', required: gettext_option)
983 libgit_dependencies += intl
984 build_options_config.set('NO_GETTEXT', '')
985 build_options_config.set('USE_GETTEXT_SCHEME', '')
987 # POSIX nowadays requires `nl_langinfo()`, but some systems still don't have
988 # the function available. On such systems we instead fall back to libcharset.
989 # On native Windows systems we use our own emulation.
990 if host_machine.system() != 'windows' and not compiler.has_function('nl_langinfo')
991 libcharset = compiler.find_library('charset', required: true)
992 libgit_dependencies += libcharset
993 libgit_c_args += '-DHAVE_LIBCHARSET_H'
996 libgit_c_args += '-DNO_GETTEXT'
997 build_options_config.set('NO_GETTEXT', '1')
998 build_options_config.set('USE_GETTEXT_SCHEME', 'fallthrough')
1001 iconv = dependency('iconv', required: get_option('iconv'))
1003 libgit_dependencies += iconv
1004 build_options_config.set('NO_ICONV', '')
1006 have_old_iconv = false
1007 if not compiler.compiles('''
1010 extern size_t iconv(iconv_t cd,
1011 char **inbuf, size_t *inbytesleft,
1012 char **outbuf, size_t *outbytesleft);
1013 ''', name: 'old iconv interface', dependencies: [iconv])
1014 libgit_c_args += '-DOLD_ICONV'
1015 have_old_iconv = true
1018 iconv_omits_bom_source = '''#
1021 int main(int argc, const char **argv)
1025 iconv_omits_bom_source += '''
1026 typedef const char *iconv_ibp;
1029 iconv_omits_bom_source += '''
1030 typedef char *iconv_ibp;
1033 iconv_omits_bom_source += '''
1036 char in[] = "a"; iconv_ibp pin = in;
1037 char out[20] = ""; char *pout = out;
1038 size_t isz = sizeof in;
1039 size_t osz = sizeof out;
1041 conv = iconv_open("UTF-16", "UTF-8");
1042 iconv(conv, &pin, &isz, &pout, &osz);
1044 v = (unsigned char)(out[0]) + (unsigned char)(out[1]);
1045 return v != 0xfe + 0xff;
1049 if compiler.run(iconv_omits_bom_source,
1050 dependencies: iconv,
1051 name: 'iconv omits BOM',
1053 libgit_c_args += '-DICONV_OMITS_BOM'
1056 libgit_c_args += '-DNO_ICONV'
1057 build_options_config.set('NO_ICONV', '1')
1060 # can't use enable_auto_if() because it is only available in meson 1.1
1061 if host_machine.system() == 'windows' and get_option('pcre2').allowed()
1062 pcre2_feature = true
1064 pcre2_feature = get_option('pcre2')
1066 pcre2 = dependency('libpcre2-8', required: pcre2_feature, default_options: ['default_library=static', 'test=false'])
1067 if pcre2.found() and pcre2.type_name() != 'internal' and host_machine.system() == 'darwin'
1068 # macOS installs a broken system package, double check
1069 if not compiler.has_header('pcre2.h', dependencies: pcre2)
1070 if pcre2_feature.enabled()
1071 pcre2_fallback = ['pcre2', 'libpcre2_8']
1075 # Attempt to fallback or replace with not-found-dependency
1076 pcre2 = dependency('', required: false, fallback: pcre2_fallback, default_options: ['default_library=static', 'test=false'])
1077 if not pcre2.found()
1078 if pcre2_feature.enabled()
1079 error('only a broken pcre2 install found and pcre2 is required')
1081 warning('broken pcre2 install found, disabling pcre2 feature')
1088 libgit_dependencies += pcre2
1089 libgit_c_args += '-DUSE_LIBPCRE2'
1090 build_options_config.set('USE_LIBPCRE2', '1')
1092 build_options_config.set('USE_LIBPCRE2', '')
1095 curl = dependency('libcurl', version: '>=7.21.3', required: get_option('curl'), default_options: ['default_library=static', 'tests=disabled', 'tool=disabled'])
1096 use_curl_for_imap_send = false
1098 if curl.version().version_compare('>=7.34.0')
1099 libgit_c_args += '-DUSE_CURL_FOR_IMAP_SEND'
1100 use_curl_for_imap_send = true
1103 # Most executables don't have to link against libcurl, but we still need its
1104 # include directories so that we can resolve LIBCURL_VERSION in "help.c".
1105 libgit_dependencies += curl.partial_dependency(includes: true)
1106 build_options_config.set('NO_CURL', '')
1108 libgit_c_args += '-DNO_CURL'
1109 build_options_config.set('NO_CURL', '1')
1112 expat = dependency('expat', required: get_option('expat'), default_options: ['default_library=static', 'build_tests=false'])
1114 libgit_dependencies += expat
1116 if expat.version().version_compare('<=1.2')
1117 libgit_c_args += '-DEXPAT_NEEDS_XMLPARSE_H'
1119 build_options_config.set('NO_EXPAT', '')
1121 libgit_c_args += '-DNO_EXPAT'
1122 build_options_config.set('NO_EXPAT', '1')
1125 if not compiler.has_header('sys/select.h')
1126 libgit_c_args += '-DNO_SYS_SELECT_H'
1129 has_poll_h = compiler.has_header('poll.h')
1131 libgit_c_args += '-DNO_POLL_H'
1134 has_sys_poll_h = compiler.has_header('sys/poll.h')
1135 if not has_sys_poll_h
1136 libgit_c_args += '-DNO_SYS_POLL_H'
1139 if not has_poll_h and not has_sys_poll_h
1140 libgit_c_args += '-DNO_POLL'
1141 libgit_sources += 'compat/poll/poll.c'
1142 libgit_include_directories += 'compat/poll'
1145 if not compiler.has_header('inttypes.h')
1146 libgit_c_args += '-DNO_INTTYPES_H'
1149 if compiler.has_header('alloca.h')
1150 libgit_c_args += '-DHAVE_ALLOCA_H'
1153 # Windows has libgen.h and a basename implementation, but we still need our own
1154 # implementation to threat things like drive prefixes specially.
1155 if host_machine.system() == 'windows' or not compiler.has_header('libgen.h')
1156 libgit_c_args += '-DNO_LIBGEN_H'
1157 libgit_sources += 'compat/basename.c'
1160 if compiler.has_header('paths.h')
1161 libgit_c_args += '-DHAVE_PATHS_H'
1164 if compiler.has_header('strings.h')
1165 libgit_c_args += '-DHAVE_STRINGS_H'
1168 networking_dependencies = [ ]
1169 if host_machine.system() == 'windows'
1170 winsock = compiler.find_library('ws2_32', required: false)
1172 networking_dependencies += winsock
1175 networking_dependencies += [
1176 compiler.find_library('nsl', required: false),
1177 compiler.find_library('resolv', required: false),
1178 compiler.find_library('socket', required: false),
1181 libgit_dependencies += networking_dependencies
1183 if host_machine.system() != 'windows'
1184 foreach symbol : ['inet_ntop', 'inet_pton', 'hstrerror']
1185 if not compiler.has_function(symbol, dependencies: networking_dependencies)
1186 libgit_c_args += '-DNO_' + symbol.to_upper()
1187 libgit_sources += 'compat/' + symbol + '.c'
1192 has_ipv6 = compiler.has_function('getaddrinfo', dependencies: networking_dependencies)
1194 libgit_c_args += '-DNO_IPV6'
1197 if not compiler.compiles('''
1199 # include <winsock2.h>
1201 # include <sys/types.h>
1202 # include <sys/socket.h>
1207 struct sockaddr_storage x;
1209 ''', name: 'struct sockaddr_storage')
1211 libgit_c_args += '-Dsockaddr_storage=sockaddr_in6'
1213 libgit_c_args += '-Dsockaddr_storage=sockaddr_in'
1217 if compiler.has_function('socket', dependencies: networking_dependencies)
1220 'unix-stream-server.c',
1222 build_options_config.set('NO_UNIX_SOCKETS', '')
1224 libgit_c_args += '-DNO_UNIX_SOCKETS'
1225 build_options_config.set('NO_UNIX_SOCKETS', '1')
1228 if host_machine.system() == 'darwin'
1229 libgit_sources += 'compat/precompose_utf8.c'
1230 libgit_c_args += '-DPRECOMPOSE_UNICODE'
1231 libgit_c_args += '-DPROTECT_HFS_DEFAULT'
1234 # Configure general compatibility wrappers.
1235 if host_machine.system() == 'cygwin'
1237 'compat/win32/path-utils.c',
1239 elif host_machine.system() == 'windows'
1242 'compat/win32/dirent.c',
1243 'compat/win32/flush.c',
1244 'compat/win32/path-utils.c',
1245 'compat/win32/pthread.c',
1246 'compat/win32/syslog.c',
1247 'compat/win32mmap.c',
1248 'compat/nedmalloc/nedmalloc.c',
1252 '-DDETECT_MSYS_TTY',
1253 '-DENSURE_MSYSTEM_IS_SET',
1256 '-DNO_POSIX_GOODIES',
1259 '-D_CONSOLE_DETECT_MSYS_TTY',
1260 '-D__USE_MINGW_ANSI_STDIO=0',
1263 libgit_dependencies += compiler.find_library('ntdll')
1264 libgit_include_directories += 'compat/win32'
1265 if compiler.get_id() == 'msvc'
1266 libgit_include_directories += 'compat/vcbuild/include'
1267 libgit_sources += 'compat/msvc.c'
1269 libgit_sources += 'compat/mingw.c'
1273 if host_machine.system() == 'linux'
1274 libgit_sources += 'compat/linux/procinfo.c'
1275 elif host_machine.system() == 'windows'
1276 libgit_sources += 'compat/win32/trace2_win32_process_info.c'
1278 libgit_sources += 'compat/stub/procinfo.c'
1281 if host_machine.system() == 'cygwin' or host_machine.system() == 'windows'
1283 '-DUNRELIABLE_FSTAT',
1284 '-DMMAP_PREVENTS_DELETE',
1285 '-DOBJECT_CREATION_MODE=1',
1289 # Configure the simple-ipc subsystem required fro the fsmonitor.
1290 if host_machine.system() == 'windows'
1292 'compat/simple-ipc/ipc-shared.c',
1293 'compat/simple-ipc/ipc-win32.c',
1295 libgit_c_args += '-DSUPPORTS_SIMPLE_IPC'
1298 'compat/simple-ipc/ipc-shared.c',
1299 'compat/simple-ipc/ipc-unix-socket.c',
1301 libgit_c_args += '-DSUPPORTS_SIMPLE_IPC'
1304 fsmonitor_backend = ''
1305 if host_machine.system() == 'windows'
1306 fsmonitor_backend = 'win32'
1307 elif host_machine.system() == 'darwin'
1308 fsmonitor_backend = 'darwin'
1309 libgit_dependencies += dependency('CoreServices')
1311 if fsmonitor_backend != ''
1312 libgit_c_args += '-DHAVE_FSMONITOR_DAEMON_BACKEND'
1313 libgit_c_args += '-DHAVE_FSMONITOR_OS_SETTINGS'
1316 'compat/fsmonitor/fsm-health-' + fsmonitor_backend + '.c',
1317 'compat/fsmonitor/fsm-ipc-' + fsmonitor_backend + '.c',
1318 'compat/fsmonitor/fsm-listen-' + fsmonitor_backend + '.c',
1319 'compat/fsmonitor/fsm-path-utils-' + fsmonitor_backend + '.c',
1320 'compat/fsmonitor/fsm-settings-' + fsmonitor_backend + '.c',
1323 build_options_config.set_quoted('FSMONITOR_DAEMON_BACKEND', fsmonitor_backend)
1324 build_options_config.set_quoted('FSMONITOR_OS_SETTINGS', fsmonitor_backend)
1326 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>') != ''
1327 build_options_config.set('NO_REGEX', '')
1329 if compiler.get_define('REG_ENHANCED', prefix: '#include <regex.h>') != ''
1330 libgit_c_args += '-DUSE_ENHANCED_BASIC_REGULAR_EXPRESSIONS'
1331 libgit_sources += 'compat/regcomp_enhanced.c'
1333 elif not get_option('regex').enabled()
1339 build_options_config.set('NO_REGEX', '1')
1340 libgit_sources += 'compat/regex/regex.c'
1341 libgit_include_directories += 'compat/regex'
1343 error('Native regex support requested but not found')
1346 # setitimer and friends are provided by compat/mingw.c.
1347 if host_machine.system() != 'windows'
1348 if not compiler.compiles('''
1349 #include <sys/time.h>
1352 struct itimerval value;
1354 ''', name: 'struct itimerval')
1355 libgit_c_args += '-DNO_STRUCT_ITIMERVAL'
1356 libgit_c_args += '-DNO_SETITIMER'
1357 elif not compiler.has_function('setitimer')
1358 libgit_c_args += '-DNO_SETITIMER'
1362 if compiler.has_member('struct stat', 'st_mtimespec.tv_nsec', prefix: '#include <sys/stat.h>')
1363 libgit_c_args += '-DUSE_ST_TIMESPEC'
1364 elif not compiler.has_member('struct stat', 'st_mtim.tv_nsec', prefix: '#include <sys/stat.h>')
1365 libgit_c_args += '-DNO_NSEC'
1368 if not compiler.has_member('struct stat', 'st_blocks', prefix: '#include <sys/stat.h>')
1369 libgit_c_args += '-DNO_ST_BLOCKS_IN_STRUCT_STAT'
1372 if not compiler.has_member('struct dirent', 'd_type', prefix: '#include <dirent.h>')
1373 libgit_c_args += '-DNO_D_TYPE_IN_DIRENT'
1376 if not compiler.has_member('struct passwd', 'pw_gecos', prefix: '#include <pwd.h>')
1377 libgit_c_args += '-DNO_GECOS_IN_PWENT'
1381 'strcasestr' : ['strcasestr.c'],
1382 'memmem' : ['memmem.c'],
1383 'strlcpy' : ['strlcpy.c'],
1385 'setenv' : ['setenv.c'],
1386 'mkdtemp' : ['mkdtemp.c'],
1388 'strtoumax' : ['strtoumax.c', 'strtoimax.c'],
1389 'pread' : ['pread.c'],
1392 if host_machine.system() == 'windows'
1393 libgit_c_args += '-DUSE_WIN32_MMAP'
1396 'mmap' : ['mmap.c'],
1397 # provided by compat/mingw.c.
1398 'unsetenv' : ['unsetenv.c'],
1399 # provided by compat/mingw.c.
1404 foreach func, impls : checkfuncs
1405 if not compiler.has_function(func)
1406 libgit_c_args += '-DNO_' + func.to_upper()
1407 foreach impl : impls
1408 libgit_sources += 'compat/' + impl
1413 if compiler.has_function('sync_file_range')
1414 libgit_c_args += '-DHAVE_SYNC_FILE_RANGE'
1417 if not compiler.has_function('strdup')
1418 libgit_c_args += '-DOVERRIDE_STRDUP'
1419 libgit_sources += 'compat/strdup.c'
1422 if not compiler.has_function('qsort')
1423 libgit_c_args += '-DINTERNAL_QSORT'
1425 libgit_sources += 'compat/qsort_s.c'
1427 if compiler.has_function('getdelim')
1428 libgit_c_args += '-DHAVE_GETDELIM'
1432 if compiler.has_function('clock_gettime')
1433 libgit_c_args += '-DHAVE_CLOCK_GETTIME'
1436 if compiler.compiles('''
1441 clockid_t id = CLOCK_MONOTONIC;
1443 ''', name: 'monotonic clock')
1444 libgit_c_args += '-DHAVE_CLOCK_MONOTONIC'
1447 has_bsd_sysctl = false
1448 if compiler.has_header('sys/sysctl.h')
1449 if compiler.compiles('''
1451 #include <sys/sysctl.h>
1455 int val, mib[2] = { 0 };
1456 size_t len = sizeof(val);
1457 sysctl(mib, 2, &val, &len, NULL, 0);
1459 ''', name: 'BSD sysctl')
1460 libgit_c_args += '-DHAVE_BSD_SYSCTL'
1461 has_bsd_sysctl = true
1465 if not has_bsd_sysctl
1466 if compiler.has_member('struct sysinfo', 'totalram', prefix: '#include <sys/sysinfo.h>')
1467 libgit_c_args += '-DHAVE_SYSINFO'
1471 if not meson.is_cross_build() and compiler.run('''
1474 int main(int argc, const char **argv)
1476 FILE *f = fopen(".", "r");
1479 ''', name: 'fread reads directories').returncode() == 0
1480 libgit_c_args += '-DFREAD_READS_DIRECTORIES'
1481 libgit_sources += 'compat/fopen.c'
1484 if not meson.is_cross_build() and fs.exists('/dev/tty')
1485 libgit_c_args += '-DHAVE_DEV_TTY'
1488 csprng_backend = get_option('csprng_backend')
1489 https_backend = get_option('https_backend')
1490 sha1_backend = get_option('sha1_backend')
1491 sha1_unsafe_backend = get_option('sha1_unsafe_backend')
1492 sha256_backend = get_option('sha256_backend')
1494 security_framework = dependency('Security', required: 'CommonCrypto' in [https_backend, sha1_backend, sha1_unsafe_backend])
1495 core_foundation_framework = dependency('CoreFoundation', required: security_framework.found())
1496 if https_backend == 'auto' and security_framework.found()
1497 https_backend = 'CommonCrypto'
1500 openssl_required = 'openssl' in [csprng_backend, https_backend, sha1_backend, sha1_unsafe_backend, sha256_backend]
1501 openssl = dependency('openssl',
1502 required: openssl_required,
1503 allow_fallback: openssl_required or https_backend == 'auto',
1504 default_options: ['default_library=static'],
1506 if https_backend == 'auto' and openssl.found()
1507 https_backend = 'openssl'
1510 if https_backend == 'CommonCrypto'
1511 libgit_dependencies += security_framework
1512 libgit_dependencies += core_foundation_framework
1513 libgit_c_args += '-DAPPLE_COMMON_CRYPTO'
1514 elif https_backend == 'openssl'
1515 libgit_dependencies += openssl
1517 # We either couldn't find any dependencies with 'auto' or the user requested
1518 # 'none'. Both cases are benign.
1519 https_backend = 'none'
1522 if https_backend != 'openssl'
1523 libgit_c_args += '-DNO_OPENSSL'
1526 if sha1_backend == 'sha1dc'
1527 libgit_c_args += '-DSHA1_DC'
1528 libgit_c_args += '-DSHA1DC_NO_STANDARD_INCLUDES=1'
1529 libgit_c_args += '-DSHA1DC_INIT_SAFE_HASH_DEFAULT=0'
1530 libgit_c_args += '-DSHA1DC_CUSTOM_INCLUDE_SHA1_C="git-compat-util.h"'
1531 libgit_c_args += '-DSHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C="git-compat-util.h"'
1536 'sha1dc/ubc_check.c',
1539 if sha1_backend == 'CommonCrypto' or sha1_unsafe_backend == 'CommonCrypto'
1540 if sha1_backend == 'CommonCrypto'
1541 libgit_c_args += '-DSHA1_APPLE'
1543 if sha1_unsafe_backend == 'CommonCrypto'
1544 libgit_c_args += '-DSHA1_APPLE_UNSAFE'
1547 libgit_c_args += '-DCOMMON_DIGEST_FOR_OPENSSL'
1548 # Apple CommonCrypto requires chunking
1549 libgit_c_args += '-DSHA1_MAX_BLOCK_SIZE=1024L*1024L*1024L'
1551 if sha1_backend == 'openssl' or sha1_unsafe_backend == 'openssl'
1552 if sha1_backend == 'openssl'
1553 libgit_c_args += '-DSHA1_OPENSSL'
1555 if sha1_unsafe_backend == 'openssl'
1556 libgit_c_args += '-DSHA1_OPENSSL_UNSAFE'
1559 libgit_dependencies += openssl
1561 if sha1_backend == 'block' or sha1_unsafe_backend == 'block'
1562 if sha1_backend == 'block'
1563 libgit_c_args += '-DSHA1_BLK'
1565 if sha1_unsafe_backend == 'block'
1566 libgit_c_args += '-DSHA1_BLK_UNSAFE'
1569 libgit_sources += 'block-sha1/sha1.c'
1572 if sha256_backend == 'openssl'
1573 libgit_c_args += '-DSHA256_OPENSSL'
1574 libgit_dependencies += openssl
1575 elif sha256_backend == 'nettle'
1576 nettle = dependency('nettle')
1577 libgit_dependencies += nettle
1578 libgit_c_args += '-DSHA256_NETTLE'
1579 elif sha256_backend == 'gcrypt'
1580 gcrypt = dependency('gcrypt')
1581 libgit_dependencies += gcrypt
1582 libgit_c_args += '-DSHA256_GCRYPT'
1583 elif sha256_backend == 'block'
1584 libgit_c_args += '-DSHA256_BLK'
1585 libgit_sources += 'sha256/block/sha256.c'
1587 error('Unhandled SHA256 backend ' + sha256_backend)
1590 # Backends are ordered to reflect our preference for more secure and faster
1591 # ones over the ones that are less so.
1592 if csprng_backend in ['auto', 'arc4random'] and compiler.has_header_symbol('stdlib.h', 'arc4random_buf', required: csprng_backend == 'arc4random')
1593 libgit_c_args += '-DHAVE_ARC4RANDOM'
1594 csprng_backend = 'arc4random'
1595 elif csprng_backend in ['auto', 'arc4random_bsd'] and compiler.has_header_symbol('bsd/stdlib.h', 'arc4random_buf', required: csprng_backend == 'arc4random_bsd')
1596 libgit_c_args += '-DHAVE_ARC4RANDOM_BSD'
1597 csprng_backend = 'arc4random_bsd'
1598 elif csprng_backend in ['auto', 'getrandom'] and compiler.has_header_symbol('sys/random.h', 'getrandom', required: csprng_backend == 'getrandom')
1599 libgit_c_args += '-DHAVE_GETRANDOM'
1600 csprng_backend = 'getrandom'
1601 elif csprng_backend in ['auto', 'getentropy'] and compiler.has_header_symbol('unistd.h', 'getentropy', required: csprng_backend == 'getentropy')
1602 libgit_c_args += '-DHAVE_GETENTROPY'
1603 csprng_backend = 'getentropy'
1604 elif csprng_backend in ['auto', 'rtlgenrandom'] and compiler.has_header_symbol('ntsecapi.h', 'RtlGenRandom', prefix: '#include <windows.h>', required: csprng_backend == 'rtlgenrandom')
1605 libgit_c_args += '-DHAVE_RTLGENRANDOM'
1606 csprng_backend = 'rtlgenrandom'
1607 elif csprng_backend in ['auto', 'openssl'] and openssl.found()
1608 libgit_c_args += '-DHAVE_OPENSSL_CSPRNG'
1609 csprng_backend = 'openssl'
1610 elif csprng_backend in ['auto', 'urandom']
1611 csprng_backend = 'urandom'
1613 error('Unsupported CSPRNG backend: ' + csprng_backend)
1616 git_exec_path = 'libexec/git-core'
1617 libexec = get_option('libexecdir')
1618 if libexec != 'libexec' and libexec != '.'
1619 git_exec_path = libexec
1622 if get_option('runtime_prefix')
1623 libgit_c_args += '-DRUNTIME_PREFIX'
1624 build_options_config.set('RUNTIME_PREFIX', 'true')
1626 if git_exec_path.startswith('/')
1627 error('runtime_prefix requires a relative libexecdir not:', libexec)
1630 if compiler.has_header('mach-o/dyld.h')
1631 libgit_c_args += '-DHAVE_NS_GET_EXECUTABLE_PATH'
1634 if has_bsd_sysctl and compiler.compiles('''
1635 #include <sys/sysctl.h>
1639 KERN_PROC_PATHNAME; KERN_PROC;
1641 ''', name: 'BSD KERN_PROC_PATHNAME')
1642 libgit_c_args += '-DHAVE_NS_GET_EXECUTABLE_PATH'
1645 if host_machine.system() == 'linux'
1646 libgit_c_args += '-DPROCFS_EXECUTABLE_PATH="/proc/self/exe' + '"'
1647 elif host_machine.system() == 'openbsd'
1648 libgit_c_args += '-DPROCFS_EXECUTABLE_PATH="' + '/proc/curproc/file' + '"'
1649 elif host_machine.system() == 'netbsd'
1650 libgit_c_args += '-DPROCFS_EXECUTABLE_PATH="' + '/proc/curproc/exe' + '"'
1653 if host_machine.system() == 'windows' and compiler.compiles('''
1660 ''', name: 'Win32 _wpgmptr')
1661 libgit_c_args += '-DHAVE_WPGMPTR'
1664 build_options_config.set('RUNTIME_PREFIX', 'false')
1666 libgit_c_args += '-DGIT_EXEC_PATH="' + git_exec_path + '"'
1668 git_version_file = custom_target(
1671 meson.current_source_dir() / 'GIT-VERSION-GEN',
1672 meson.current_source_dir(),
1676 input: meson.current_source_dir() / 'GIT-VERSION-FILE.in',
1677 output: 'GIT-VERSION-FILE',
1678 env: version_gen_environment,
1679 build_always_stale: true,
1682 version_def_h = custom_target(
1685 meson.current_source_dir() / 'GIT-VERSION-GEN',
1686 meson.current_source_dir(),
1690 input: meson.current_source_dir() / 'version-def.h.in',
1691 output: 'version-def.h',
1692 # Depend on GIT-VERSION-FILE so that we don't always try to rebuild this
1693 # target for the same commit.
1694 depends: [git_version_file],
1695 env: version_gen_environment,
1697 libgit_sources += version_def_h
1699 libgit = declare_dependency(
1700 link_with: static_library('git',
1701 sources: libgit_sources,
1702 c_args: libgit_c_args + [
1703 '-DGIT_VERSION_H="' + version_def_h.full_path() + '"',
1705 dependencies: libgit_dependencies,
1706 include_directories: libgit_include_directories,
1708 compile_args: libgit_c_args,
1709 dependencies: libgit_dependencies,
1710 include_directories: libgit_include_directories,
1713 common_main_sources = ['common-main.c']
1714 common_main_link_args = [ ]
1715 if host_machine.system() == 'windows'
1716 git_rc = custom_target(
1719 meson.current_source_dir() / 'GIT-VERSION-GEN',
1720 meson.current_source_dir(),
1724 input: meson.current_source_dir() / 'git.rc.in',
1726 depends: [git_version_file],
1727 env: version_gen_environment,
1730 common_main_sources += import('windows').compile_resources(git_rc,
1731 include_directories: [meson.current_source_dir()],
1733 if compiler.get_argument_syntax() == 'gcc'
1734 common_main_link_args += [
1738 '-Wl,-pic-executable,-e,mainCRTStartup',
1740 elif compiler.get_argument_syntax() == 'msvc'
1741 common_main_link_args += [
1742 '/ENTRY:wmainCRTStartup',
1743 'invalidcontinue.obj',
1746 error('Unsupported compiler ' + compiler.get_id())
1750 libgit_commonmain = declare_dependency(
1751 link_with: static_library('common-main',
1752 sources: common_main_sources,
1753 dependencies: [ libgit ],
1755 link_args: common_main_link_args,
1756 dependencies: [ libgit ],
1760 test_dependencies = [ ]
1762 git_builtin = executable('git',
1763 sources: builtin_sources + 'git.c',
1764 dependencies: [libgit_commonmain],
1766 install_dir: git_exec_path,
1768 bin_wrappers += git_builtin
1770 test_dependencies += executable('git-daemon',
1771 sources: 'daemon.c',
1772 dependencies: [libgit_commonmain],
1774 install_dir: git_exec_path,
1777 test_dependencies += executable('git-sh-i18n--envsubst',
1778 sources: 'sh-i18n--envsubst.c',
1779 dependencies: [libgit_commonmain],
1781 install_dir: git_exec_path,
1784 bin_wrappers += executable('git-shell',
1786 dependencies: [libgit_commonmain],
1788 install_dir: git_exec_path,
1791 test_dependencies += executable('git-http-backend',
1792 sources: 'http-backend.c',
1793 dependencies: [libgit_commonmain],
1795 install_dir: git_exec_path,
1798 bin_wrappers += executable('scalar',
1799 sources: 'scalar.c',
1800 dependencies: [libgit_commonmain],
1802 install_dir: git_exec_path,
1806 libgit_curl = declare_dependency(
1811 dependencies: [libgit_commonmain, curl],
1814 test_dependencies += executable('git-remote-http',
1815 sources: 'remote-curl.c',
1816 dependencies: [libgit_curl],
1818 install_dir: git_exec_path,
1821 test_dependencies += executable('git-http-fetch',
1822 sources: 'http-fetch.c',
1823 dependencies: [libgit_curl],
1825 install_dir: git_exec_path,
1829 test_dependencies += executable('git-http-push',
1830 sources: 'http-push.c',
1831 dependencies: [libgit_curl],
1833 install_dir: git_exec_path,
1837 foreach alias : [ 'git-remote-https', 'git-remote-ftp', 'git-remote-ftps' ]
1838 test_dependencies += executable(alias,
1839 sources: 'remote-curl.c',
1840 dependencies: [libgit_curl],
1843 install_symlink(alias + executable_suffix,
1844 install_dir: git_exec_path,
1845 pointing_to: 'git-remote-http',
1850 test_dependencies += executable('git-imap-send',
1851 sources: 'imap-send.c',
1852 dependencies: [ use_curl_for_imap_send ? libgit_curl : libgit_commonmain ],
1854 install_dir: git_exec_path,
1857 foreach alias : [ 'git-receive-pack', 'git-upload-archive', 'git-upload-pack' ]
1858 bin_wrappers += executable(alias,
1859 objects: git_builtin.extract_all_objects(recursive: false),
1860 dependencies: [libgit_commonmain],
1863 install_symlink(alias + executable_suffix,
1864 install_dir: git_exec_path,
1873 'git-upload-archive',
1877 if meson.version().version_compare('>=1.3.0')
1878 pointing_to = fs.relative_to(git_exec_path / symlink, get_option('bindir'))
1880 pointing_to = '..' / git_exec_path / symlink
1883 install_symlink(symlink,
1884 install_dir: get_option('bindir'),
1885 pointing_to: pointing_to,
1890 'git-difftool--helper.sh',
1891 'git-filter-branch.sh',
1892 'git-merge-octopus.sh',
1893 'git-merge-one-file.sh',
1894 'git-merge-resolve.sh',
1895 'git-mergetool--lib.sh',
1897 'git-quiltimport.sh',
1898 'git-request-pull.sh',
1902 'git-web--browse.sh',
1904 if perl_features_enabled
1905 scripts_sh += 'git-instaweb.sh'
1908 foreach script : scripts_sh
1909 test_dependencies += custom_target(
1911 output: fs.stem(script),
1914 meson.project_source_root() / 'generate-script.sh',
1917 meson.project_build_root() / 'GIT-BUILD-OPTIONS',
1920 install_dir: git_exec_path,
1924 if perl_features_enabled
1926 'git-archimport.perl',
1927 'git-cvsexportcommit.perl',
1928 'git-cvsimport.perl',
1929 'git-cvsserver.perl',
1930 'git-send-email.perl',
1935 if host_machine.system() == 'windows'
1939 perl_header_template = 'perl/header_templates/fixed_prefix.template.pl'
1940 if get_option('runtime_prefix')
1941 perl_header_template = 'perl/header_templates/runtime_prefix.template.pl'
1944 perllibdir = get_option('perllibdir')
1946 perllibdir = get_option('datadir') / 'perl5'
1949 perl_header = configure_file(
1950 input: perl_header_template,
1951 output: 'GIT-PERL-HEADER',
1953 'GITEXECDIR_REL': git_exec_path,
1954 'PERLLIBDIR_REL': perllibdir,
1955 'LOCALEDIR_REL': get_option('datadir') / 'locale',
1956 'INSTLIBDIR': perllibdir,
1961 generate_perl_command = [
1963 meson.project_source_root() / 'generate-perl.sh',
1964 meson.project_build_root() / 'GIT-BUILD-OPTIONS',
1965 git_version_file.full_path(),
1971 foreach script : scripts_perl
1972 generated_script = custom_target(
1974 output: fs.stem(script),
1975 command: generate_perl_command,
1977 install_dir: git_exec_path,
1978 depends: [git_version_file],
1980 test_dependencies += generated_script
1982 if script == 'git-cvsserver.perl'
1983 bin_wrappers += generated_script
1985 if meson.version().version_compare('>=1.3.0')
1986 pointing_to = fs.relative_to(git_exec_path / fs.stem(script), get_option('bindir'))
1988 pointing_to = '..' / git_exec_path / fs.stem(script)
1991 install_symlink(fs.stem(script),
1992 install_dir: get_option('bindir'),
1993 pointing_to: pointing_to,
2001 if target_python.found()
2006 foreach script : scripts_python
2007 generated_python = custom_target(
2009 output: fs.stem(script),
2012 meson.project_source_root() / 'generate-python.sh',
2013 meson.project_build_root() / 'GIT-BUILD-OPTIONS',
2018 install_dir: git_exec_path,
2020 test_dependencies += generated_python
2025 'mergetools/araxis',
2027 'mergetools/codecompare',
2028 'mergetools/deltawalker',
2029 'mergetools/diffmerge',
2030 'mergetools/diffuse',
2031 'mergetools/ecmerge',
2032 'mergetools/emerge',
2033 'mergetools/examdiff',
2034 'mergetools/guiffy',
2035 'mergetools/gvimdiff',
2036 'mergetools/kdiff3',
2037 'mergetools/kompare',
2039 'mergetools/nvimdiff',
2040 'mergetools/opendiff',
2041 'mergetools/p4merge',
2042 'mergetools/smerge',
2043 'mergetools/tkdiff',
2044 'mergetools/tortoisemerge',
2045 'mergetools/vimdiff',
2046 'mergetools/vscode',
2047 'mergetools/winmerge',
2048 'mergetools/xxdiff',
2051 foreach mergetool : mergetools
2052 install_data(mergetool, install_dir: git_exec_path / 'mergetools')
2059 # Gitweb requires Perl, so we disable the auto-feature if Perl was not found.
2060 # We make sure further up that Perl is required in case the gitweb option is
2062 gitweb_option = get_option('gitweb').disable_auto_if(not perl.found())
2063 if gitweb_option.allowed()
2065 build_options_config.set('NO_GITWEB', '')
2067 build_options_config.set('NO_GITWEB', '1')
2072 # Everything but the bin-wrappers need to come before this target such that we
2073 # can properly set up test dependencies. The bin-wrappers themselves are set up
2074 # at configuration time, so these are fine.
2075 if get_option('tests')
2080 # The TAP protocol was already understood by previous versions of Meson, but
2081 # it was incompatible with the `meson test --interactive` flag.
2082 if meson.version().version_compare('>=1.8.0')
2091 if get_option('fuzzers')
2095 subdir('bin-wrappers')
2096 if get_option('docs') != []
2097 subdir('Documentation')
2102 exclude_from_check_headers = [
2107 if sha1_backend != 'openssl'
2108 exclude_from_check_headers += 'sha1/openssl.h'
2110 if sha256_backend != 'openssl'
2111 exclude_from_check_headers += 'sha256/openssl.h'
2113 if sha256_backend != 'nettle'
2114 exclude_from_check_headers += 'sha256/nettle.h'
2116 if sha256_backend != 'gcrypt'
2117 exclude_from_check_headers += 'sha256/gcrypt.h'
2120 if headers_to_check.length() != 0 and compiler.get_argument_syntax() == 'gcc'
2122 foreach h : headers_to_check
2124 foreach exclude : exclude_from_check_headers
2125 if h.startswith(exclude)
2135 hcc = custom_target(
2137 output: h.underscorify() + 'cc',
2141 'echo \'#include "git-compat-util.h"\' > @OUTPUT@ && echo \'#include "' + h + '"\' >> @OUTPUT@'
2145 hco = custom_target(
2147 output: fs.replace_suffix(h.underscorify(), '.hco'),
2149 compiler.cmd_array(),
2151 '-I', meson.project_source_root(),
2152 '-I', meson.project_source_root() / 't/unit-tests',
2161 # TODO: deprecate 'hdr-check' in lieu of 'check-headers' in Git 2.51+
2162 hdr_check = alias_target('hdr-check', hco_targets)
2163 alias_target('check-headers', hdr_check)
2166 git_clang_format = find_program('git-clang-format', required: false, native: true)
2167 if git_clang_format.found()
2173 '--extensions', 'c,h'
2178 foreach key, value : {
2179 'DIFF': diff.full_path(),
2180 'GIT_SOURCE_DIR': meson.project_source_root(),
2181 'GIT_TEST_CMP': diff.full_path() + ' -u',
2182 'GIT_TEST_GITPERLLIB': meson.project_build_root() / 'perl',
2183 'GIT_TEST_TEMPLATE_DIR': meson.project_build_root() / 'templates',
2184 'GIT_TEST_TEXTDOMAINDIR': meson.project_build_root() / 'po',
2185 'PAGER_ENV': get_option('pager_environment'),
2186 'PERL_PATH': target_perl.found() ? target_perl.full_path() : '',
2187 'PYTHON_PATH': target_python.found () ? target_python.full_path() : '',
2188 'SHELL_PATH': target_shell.full_path(),
2189 'TAR': tar.full_path(),
2190 'TEST_OUTPUT_DIRECTORY': test_output_directory,
2191 'TEST_SHELL_PATH': shell.full_path(),
2193 if value != '' and cygpath.found()
2194 value = run_command(cygpath, value, check: true).stdout().strip()
2196 build_options_config.set_quoted(key, value)
2200 input: 'GIT-BUILD-OPTIONS.in',
2201 output: 'GIT-BUILD-OPTIONS',
2202 configuration: build_options_config,
2205 # Development environments can be used via `meson devenv -C <builddir>`. This
2206 # allows you to execute test scripts directly with the built Git version and
2207 # puts the built version of Git in your PATH.
2208 devenv = environment()
2209 devenv.set('GIT_BUILD_DIR', meson.current_build_dir())
2210 devenv.prepend('PATH', meson.current_build_dir() / 'bin-wrappers')
2211 meson.add_devenv(devenv)
2213 # Generate the 'version' file in the distribution tarball. This is used via
2214 # `meson dist -C <builddir>` to populate the source archive with the Git
2215 # version that the archive is being generated from.
2216 meson.add_dist_script(
2219 '"$1" "$2" "$3" --format="@GIT_VERSION@" "$MESON_DIST_ROOT/version"',
2222 meson.current_source_dir() / 'GIT-VERSION-GEN',
2223 meson.current_source_dir(),
2227 'benchmarks': get_option('tests') and perl.found() and time.found(),
2231 'gitweb': gitweb_option.allowed(),
2234 'perl': perl_features_enabled,
2235 'python': target_python.found(),
2236 }, section: 'Auto-detected features', bool_yn: true)
2239 'csprng': csprng_backend,
2240 'https': https_backend,
2241 'sha1': sha1_backend,
2242 'sha1_unsafe': sha1_unsafe_backend,
2243 'sha256': sha256_backend,
2244 'zlib': zlib_backend,
2245 }, section: 'Backends')
2248 'perl': target_perl,
2249 'python': target_python,
2250 'shell': target_shell,
2251 }, section: 'Runtime executable paths')