Git fork

meson: distinguish build and target host binaries

Almost all of the tools we discover during the build process need to be
native programs. There are only a handful of exceptions, which typically
are programs whose paths we need to embed into the resulting executable
so that they can be found on the target system when Git executes. While
this distinction typically doesn't matter, it does start to matter when
considering cross-compilation where the build and target machines are
different.

Meson supports cross-compilation via so-called machine files. These
machine files allow the user to override parameters for the build
machine, but also for the target machine when cross-compiling. Part of
the machine file is a section that allows the user to override the
location where binaries are to be found in the target system. The
following machine file would for example override the path of the POSIX
shell:

[binaries]
sh = '/usr/xpg4/bin/sh'

It can be handed over to Meson via `meson setup --cross-file`.

We do not handle this correctly right now though because we don't know
to distinguish binaries for the build and target hosts at all. Address
this by explicitly passing the `native:` parameter to `find_program()`:

- When set to `true`, we get binaries discovered on the build host.

- When set to `false`, we get either the path specified in the
machine file. Or, if no machine file exists or it doesn't specify
the binary path, then we fall back to the binary discovered on the
build host.

As mentioned, only a handful of binaries are not native: only the system
shell, Python and Perl need to be treated specially here.

Reported-by: Peter Seiderer <ps.report@gmx.net>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>

authored by

Patrick Steinhardt and committed by
Junio C Hamano
23633466 bdd04b91

+60 -24
+6 -6
Documentation/meson.build
··· 207 208 docs_backend = get_option('docs_backend') 209 if docs_backend == 'auto' 210 - if find_program('asciidoc', dirs: program_path, required: false).found() 211 docs_backend = 'asciidoc' 212 - elif find_program('asciidoctor', dirs: program_path, required: false).found() 213 docs_backend = 'asciidoctor' 214 else 215 error('Neither asciidoc nor asciidoctor were found.') ··· 217 endif 218 219 if docs_backend == 'asciidoc' 220 - asciidoc = find_program('asciidoc', dirs: program_path) 221 asciidoc_html = 'xhtml11' 222 asciidoc_docbook = 'docbook' 223 xmlto_extra = [ ] ··· 246 asciidoc_conf, 247 ] 248 elif docs_backend == 'asciidoctor' 249 - asciidoctor = find_program('asciidoctor', dirs: program_path) 250 asciidoc_html = 'xhtml5' 251 asciidoc_docbook = 'docbook5' 252 xmlto_extra = [ ··· 288 asciidoc_common_options += ['--attribute', 'with-breaking-changes'] 289 endif 290 291 - xmlto = find_program('xmlto', dirs: program_path) 292 293 cmd_lists = [ 294 'cmds-ancillaryinterrogators.adoc', ··· 409 pointing_to: 'git.html', 410 ) 411 412 - xsltproc = find_program('xsltproc', dirs: program_path) 413 414 user_manual_xml = custom_target( 415 command: asciidoc_common_options + [
··· 207 208 docs_backend = get_option('docs_backend') 209 if docs_backend == 'auto' 210 + if find_program('asciidoc', dirs: program_path, native: true, required: false).found() 211 docs_backend = 'asciidoc' 212 + elif find_program('asciidoctor', dirs: program_path, native: true, required: false).found() 213 docs_backend = 'asciidoctor' 214 else 215 error('Neither asciidoc nor asciidoctor were found.') ··· 217 endif 218 219 if docs_backend == 'asciidoc' 220 + asciidoc = find_program('asciidoc', dirs: program_path, native: true) 221 asciidoc_html = 'xhtml11' 222 asciidoc_docbook = 'docbook' 223 xmlto_extra = [ ] ··· 246 asciidoc_conf, 247 ] 248 elif docs_backend == 'asciidoctor' 249 + asciidoctor = find_program('asciidoctor', dirs: program_path, native: true) 250 asciidoc_html = 'xhtml5' 251 asciidoc_docbook = 'docbook5' 252 xmlto_extra = [ ··· 288 asciidoc_common_options += ['--attribute', 'with-breaking-changes'] 289 endif 290 291 + xmlto = find_program('xmlto', dirs: program_path, native: true) 292 293 cmd_lists = [ 294 'cmds-ancillaryinterrogators.adoc', ··· 409 pointing_to: 'git.html', 410 ) 411 412 + xsltproc = find_program('xsltproc', dirs: program_path, native: true) 413 414 user_manual_xml = custom_target( 415 command: asciidoc_common_options + [
+1 -1
gitweb/meson.build
··· 1 gitweb_config = configuration_data() 2 - gitweb_config.set_quoted('PERL_PATH', perl.full_path()) 3 gitweb_config.set_quoted('CSSMIN', '') 4 gitweb_config.set_quoted('JSMIN', '') 5 gitweb_config.set_quoted('GIT_BINDIR', get_option('prefix') / get_option('bindir'))
··· 1 gitweb_config = configuration_data() 2 + gitweb_config.set_quoted('PERL_PATH', target_perl.full_path()) 3 gitweb_config.set_quoted('CSSMIN', '') 4 gitweb_config.set_quoted('JSMIN', '') 5 gitweb_config.set_quoted('GIT_BINDIR', get_option('prefix') / get_option('bindir'))
+51 -15
meson.build
··· 155 # These machine files can be passed to `meson setup` via the `--native-file` 156 # option. 157 # 158 # Subproject wrappers 159 # =================== 160 # ··· 173 # The version is only of cosmetic nature, so if we cannot find a shell yet we 174 # simply don't set up a version at all. This may be the case for example on 175 # Windows systems, where we first have to bootstrap the host environment. 176 - version: find_program('sh', required: false).found() ? run_command( 177 'GIT-VERSION-GEN', meson.current_source_dir(), '--format=@GIT_VERSION@', 178 capture: true, 179 check: true, ··· 198 program_path = [ 'C:/Program Files/Git/bin', 'C:/Program Files/Git/usr/bin' ] 199 endif 200 201 - cygpath = find_program('cygpath', dirs: program_path, required: false) 202 - diff = find_program('diff', dirs: program_path) 203 - git = find_program('git', dirs: program_path, required: false) 204 - sed = find_program('sed', dirs: program_path) 205 - shell = find_program('sh', dirs: program_path) 206 - tar = find_program('tar', dirs: program_path) 207 208 # Sanity-check that programs required for the build exist. 209 foreach tool : ['cat', 'cut', 'grep', 'sort', 'tr', 'uname'] 210 - find_program(tool, dirs: program_path) 211 endforeach 212 213 script_environment = environment() ··· 706 '-DGIT_LOCALE_PATH="' + get_option('localedir') + '"', 707 '-DGIT_MAN_PATH="' + get_option('mandir') + '"', 708 '-DPAGER_ENV="' + get_option('pager_environment') + '"', 709 - '-DSHELL_PATH="' + fs.as_posix(shell.full_path()) + '"', 710 ] 711 libgit_include_directories = [ '.' ] 712 libgit_dependencies = [ ] ··· 761 build_options_config.set_quoted('X', executable_suffix) 762 763 python = import('python').find_installation('python3', required: get_option('python')) 764 if python.found() 765 build_options_config.set('NO_PYTHON', '') 766 else ··· 790 # which we can do starting with Meson 1.5.0 and newer, or we have to 791 # match against the minor version. 792 if meson.version().version_compare('>=1.5.0') 793 - perl = find_program('perl', dirs: program_path, required: perl_required, version: '>=5.26.0', version_argument: '-V:version') 794 else 795 - perl = find_program('perl', dirs: program_path, required: perl_required, version: '>=26') 796 endif 797 perl_features_enabled = perl.found() and get_option('perl').allowed() 798 if perl_features_enabled ··· 843 build_options_config.set('NO_PTHREADS', '1') 844 endif 845 846 - msgfmt = find_program('msgfmt', dirs: program_path, required: false) 847 gettext_option = get_option('gettext').disable_auto_if(not msgfmt.found()) 848 if not msgfmt.found() and gettext_option.enabled() 849 error('Internationalization via libintl requires msgfmt') ··· 1974 'GIT_TEST_TEMPLATE_DIR': meson.project_build_root() / 'templates', 1975 'GIT_TEST_TEXTDOMAINDIR': meson.project_build_root() / 'po', 1976 'PAGER_ENV': get_option('pager_environment'), 1977 - 'PERL_PATH': perl.found() ? perl.full_path() : '', 1978 - 'PYTHON_PATH': python.found () ? python.full_path() : '', 1979 - 'SHELL_PATH': shell.full_path(), 1980 'TAR': tar.full_path(), 1981 'TEST_OUTPUT_DIRECTORY': test_output_directory, 1982 'TEST_SHELL_PATH': shell.full_path(),
··· 155 # These machine files can be passed to `meson setup` via the `--native-file` 156 # option. 157 # 158 + # Cross compilation 159 + # ================= 160 + # 161 + # Machine files can also be used in the context of cross-compilation to 162 + # describe the target machine as well as the cross-compiler toolchain that 163 + # shall be used. An example machine file could look like the following: 164 + # 165 + # [binaries] 166 + # c = 'x86_64-w64-mingw32-gcc' 167 + # cpp = 'x86_64-w64-mingw32-g++' 168 + # ar = 'x86_64-w64-mingw32-ar' 169 + # windres = 'x86_64-w64-mingw32-windres' 170 + # strip = 'x86_64-w64-mingw32-strip' 171 + # exe_wrapper = 'wine64' 172 + # sh = 'C:/Program Files/Git for Windows/usr/bin/sh.exe' 173 + # 174 + # [host_machine] 175 + # system = 'windows' 176 + # cpu_family = 'x86_64' 177 + # cpu = 'x86_64' 178 + # endian = 'little' 179 + # 180 + # These machine files can be passed to `meson setup` via the `--cross-file` 181 + # option. 182 + # 183 + # Note that next to the cross-compiler toolchain, the `[binaries]` section is 184 + # also used to locate a couple of binaries that will be built into Git. This 185 + # includes `sh`, `python` and `perl`, so when cross-compiling Git you likely 186 + # want to set these binary paths in addition to the cross-compiler toolchain 187 + # binaries. 188 + # 189 # Subproject wrappers 190 # =================== 191 # ··· 204 # The version is only of cosmetic nature, so if we cannot find a shell yet we 205 # simply don't set up a version at all. This may be the case for example on 206 # Windows systems, where we first have to bootstrap the host environment. 207 + version: find_program('sh', native: true, required: false).found() ? run_command( 208 'GIT-VERSION-GEN', meson.current_source_dir(), '--format=@GIT_VERSION@', 209 capture: true, 210 check: true, ··· 229 program_path = [ 'C:/Program Files/Git/bin', 'C:/Program Files/Git/usr/bin' ] 230 endif 231 232 + cygpath = find_program('cygpath', dirs: program_path, native: true, required: false) 233 + diff = find_program('diff', dirs: program_path, native: true) 234 + git = find_program('git', dirs: program_path, native: true, required: false) 235 + sed = find_program('sed', dirs: program_path, native: true) 236 + shell = find_program('sh', dirs: program_path, native: true) 237 + tar = find_program('tar', dirs: program_path, native: true) 238 + 239 + target_shell = find_program('sh', dirs: program_path, native: false) 240 241 # Sanity-check that programs required for the build exist. 242 foreach tool : ['cat', 'cut', 'grep', 'sort', 'tr', 'uname'] 243 + find_program(tool, dirs: program_path, native: true) 244 endforeach 245 246 script_environment = environment() ··· 739 '-DGIT_LOCALE_PATH="' + get_option('localedir') + '"', 740 '-DGIT_MAN_PATH="' + get_option('mandir') + '"', 741 '-DPAGER_ENV="' + get_option('pager_environment') + '"', 742 + '-DSHELL_PATH="' + fs.as_posix(target_shell.full_path()) + '"', 743 ] 744 libgit_include_directories = [ '.' ] 745 libgit_dependencies = [ ] ··· 794 build_options_config.set_quoted('X', executable_suffix) 795 796 python = import('python').find_installation('python3', required: get_option('python')) 797 + target_python = find_program('python3', native: false, required: python.found()) 798 if python.found() 799 build_options_config.set('NO_PYTHON', '') 800 else ··· 824 # which we can do starting with Meson 1.5.0 and newer, or we have to 825 # match against the minor version. 826 if meson.version().version_compare('>=1.5.0') 827 + perl = find_program('perl', dirs: program_path, native: true, required: perl_required, version: '>=5.26.0', version_argument: '-V:version') 828 + target_perl = find_program('perl', dirs: program_path, native: false, required: perl.found(), version: '>=5.26.0', version_argument: '-V:version') 829 else 830 + perl = find_program('perl', dirs: program_path, native: true, required: perl_required, version: '>=26') 831 + target_perl = find_program('perl', dirs: program_path, native: false, required: perl.found(), version: '>=26') 832 endif 833 perl_features_enabled = perl.found() and get_option('perl').allowed() 834 if perl_features_enabled ··· 879 build_options_config.set('NO_PTHREADS', '1') 880 endif 881 882 + msgfmt = find_program('msgfmt', dirs: program_path, native: true, required: false) 883 gettext_option = get_option('gettext').disable_auto_if(not msgfmt.found()) 884 if not msgfmt.found() and gettext_option.enabled() 885 error('Internationalization via libintl requires msgfmt') ··· 2010 'GIT_TEST_TEMPLATE_DIR': meson.project_build_root() / 'templates', 2011 'GIT_TEST_TEXTDOMAINDIR': meson.project_build_root() / 'po', 2012 'PAGER_ENV': get_option('pager_environment'), 2013 + 'PERL_PATH': target_perl.found() ? target_perl.full_path() : '', 2014 + 'PYTHON_PATH': target_python.found () ? target_python.full_path() : '', 2015 + 'SHELL_PATH': target_shell.full_path(), 2016 'TAR': tar.full_path(), 2017 'TEST_OUTPUT_DIRECTORY': test_output_directory, 2018 'TEST_SHELL_PATH': shell.full_path(),
+2 -2
templates/meson.build
··· 1 template_config = configuration_data() 2 - template_config.set('PERL_PATH', perl.found() ? fs.as_posix(perl.full_path()) : '') 3 - template_config.set('SHELL_PATH', fs.as_posix(shell.full_path())) 4 template_config.set('GITWEBDIR', fs.as_posix(get_option('prefix') / get_option('datadir') / 'gitweb')) 5 6 configure_file(
··· 1 template_config = configuration_data() 2 + template_config.set('PERL_PATH', target_perl.found() ? fs.as_posix(target_perl.full_path()) : '') 3 + template_config.set('SHELL_PATH', fs.as_posix(target_shell.full_path())) 4 template_config.set('GITWEBDIR', fs.as_posix(get_option('prefix') / get_option('datadir') / 'gitweb')) 5 6 configure_file(