Combinatorial explosion and... some documentation gaps? Consider this is as a github issue with a lot of code. I tried to find in the documentation all the places {cpp,c,ld}_args could be set and the relationships between these places. However what I found was scattered in the corresponding places - no single, high-level list or overview - and seemed sometimes incomplete. I searched github for the same topic but that didn't really help either because most of it is or was of course "work in progress" (the difference between "is" and "was" being not always immediately obvious) For instance https://github.com/mesonbuild/meson/issues/4767 states "All cross compilation arguments come from the cross file". Except for: -D, project(default_options: c_args...), executable( c_args, native:false),... Then I looked for some relevant test code that would be in a less natural language but necessarily in sync with the current implementation. I couldn't really find any, so I wrote this (long) sample. While tedious, this helped me understand some of the situation better. I'm not sure exactly where to take this next. A new, "<lang>_args hub" documentation node with an organized list of pointers would probably not hurt. Another cool thing would be to convert some of this to fully automated tests and it's probably not too far from it, except for the important question of: what particular combinations should be tested? Can't test everything due to the number of locations and the combinatorial explosion.pull/6362/head
parent
9c72d0fdb2
commit
40864d35cb
5 changed files with 342 additions and 0 deletions
@ -0,0 +1,90 @@ |
||||
What happens when c_args come from multiple places? |
||||
|
||||
Combinatorial explosion and... some documentation gaps? |
||||
|
||||
I tried to find in the documentation all the places {cpp,c,ld}_args |
||||
could be set and the relationships between these places. However what I |
||||
found was scattered in the corresponding places - no single, high-level |
||||
list or overview - and seemed sometimes incomplete. |
||||
|
||||
I searched github for the same topic but that didn't really help either |
||||
because most of it is or was of course "work in progress" (the |
||||
difference between "is" and "was" being not always immediately obvious) |
||||
For instance https://github.com/mesonbuild/meson/issues/4767 states "All |
||||
cross compilation arguments come from the cross file". Except for: -D, |
||||
project(default_options: c_args...), executable( c_args, native:false),... |
||||
|
||||
Then I looked for some relevant test code that would be in a less |
||||
natural language but necessarily in sync with the current |
||||
implementation. I couldn't really find any, so I wrote this (long) |
||||
sample. While tedious, this helped me understand some of the situation |
||||
better. |
||||
|
||||
I'm not sure exactly where to take this next. A new, "<lang>_args hub" |
||||
documentation node with an organized list of pointers would probably not |
||||
hurt. Another cool thing would be to convert some of this to fully |
||||
automated tests and it's probably not too far from it, except for the |
||||
important question of: what particular combinations should be tested? |
||||
Can't test everything due to the number of locations and the |
||||
combinatorial explosion. |
||||
|
||||
|
||||
Locations "under test": |
||||
- environment C/CPP/LDFLAGS |
||||
- meson setup -Dc*_args=-D... |
||||
- meson setup --cross-file c*_args |
||||
- project (default_options c*_args) |
||||
- executable (c*_args) |
||||
|
||||
Any I forgot? |
||||
- CFLAGS_FOR_BUILD ? |
||||
- multiple --cross-file (https://github.com/mesonbuild/meson/issues/3878) |
||||
|
||||
|
||||
Results below reproduced with this test directory + meson version 9c72d0fdb287. |
||||
|
||||
|
||||
A. My top issue: while some c*_args of different locations append to |
||||
each other (in which order?), other combinations of c*_args overwrite |
||||
one another and it feels difficult to predict what will happen when. |
||||
|
||||
1 "meson setup -D[build.]c_args=..." overrides" |
||||
2. "project(default_options: [build.]c_args)", which overrides: |
||||
3. env LD/C/CPPFLAGS and --cross-file c_args. |
||||
|
||||
Either of the above _combines_ with "executable(c_args)". And with |
||||
everything else? It could work differently, for instance one could |
||||
assume "project(default_options: )" means "default when no |
||||
executable(c_args)" instead. |
||||
|
||||
I would also like -Dbuild.c_args to combine with --cross-file c_args, |
||||
because why not? |
||||
|
||||
|
||||
B. environment CPP/C/LDFLAGS |
||||
|
||||
Granted: environment variables are discouraged. Still, it would be nice |
||||
to have some clearer idea how they work right now, even if nothing's |
||||
guaranteed in the future. |
||||
|
||||
When cross-compiling, the env CFLAGS and LDFLAGS affects only the build |
||||
machine. Documented? |
||||
|
||||
project(build.c_args) overrides BOTH env CPPCFLAGS and CFLAGS! |
||||
project(build.cpp_args) does... nothing ever? |
||||
|
||||
|
||||
C. Some "unknown options: build.c_*_args, ... " are actually used by meson. |
||||
|
||||
meson setup -Dbuild.cpp_args=... -Dbuild.c_args=... -Dbuild.c_link_args=... reports: |
||||
|
||||
WARNING: Unknown options: "build.c_*_args, ... |
||||
|
||||
It does drop build.cpp_args as claimed, however it uses the other two |
||||
anyway when native:true. |
||||
|
||||
|
||||
D. --cross_file cpp_args are silently ignored. It's because everything |
||||
is free-form in a --cross-file as documented, however it's another |
||||
example of the "ugly duckling" status of cpp_args in general. |
||||
|
@ -0,0 +1,75 @@ |
||||
#!/bin/sh |
||||
|
||||
set -e |
||||
set -x |
||||
|
||||
MESON=~/meson/meson.py |
||||
|
||||
|
||||
# "-Wl,--undefined=_test_value" has for the linker useful test |
||||
# properties similar to how D_test_value behaves for the preprocessor: |
||||
# visible and testable yet "pass-through" and completely harmless. In a |
||||
# way it's even better than -D because a dummy test program ends up with |
||||
# a large noise of -D macros that the toolchain adds by default, whereas |
||||
# "-Wl,--undefined=_test_value" doesn't even need to be filtered. |
||||
|
||||
do_bld() |
||||
{ |
||||
local bld="$1"; shift |
||||
if true; then |
||||
${MESON} setup \ |
||||
-Dcpp_args=-DCLIsetup_CPP_args=___YES_CLIsetup___ \ |
||||
-Dbuild.cpp_args=-DCLIsetup_buildm_CPP_args=___YES_CLIsetup_buildm____ \ |
||||
-Dc_args=-DCLIsetup_C_args=___YES_CLIsetup____ \ |
||||
-Dbuild.c_args=-DCLIsetup_buildm_C_args=___YES_CLIsetup_buildm____ \ |
||||
-Dc_link_args=-Wl,--undefined=CLIsetup_C_link_args \ |
||||
-Dbuild.c_link_args=-Wl,--undefined=CLIsetup_buildm_C_link_args \ |
||||
"$bld" "$@" |
||||
else |
||||
${MESON} setup "$bld" "$@" |
||||
fi |
||||
|
||||
${MESON} configure "$bld" | grep -C2 args |
||||
ninja -C "$bld" print_flags |
||||
|
||||
if true; then |
||||
jq . "${bld}"/meson-info/intro-buildoptions.json | grep -C 5 args |
||||
jq . "${bld}"/meson-info/intro-targets.json | grep -C 8 _args |
||||
fi |
||||
} |
||||
|
||||
main() |
||||
{ |
||||
local YES_SIR='___YES_ENV___' |
||||
|
||||
# envvars considered harmful: |
||||
# https://github.com/mesonbuild/meson/issues/4664 |
||||
if true; then |
||||
export CPPFLAGS="-Denv_CPPFLAGS=${YES_SIR}" |
||||
export CFLAGS="-Denv_CFLAGS=${YES_SIR}" |
||||
export LDFLAGS='-Wl,--undefined=env_LDFLAGS' |
||||
fi |
||||
|
||||
# --wipe fails when bld*/ is missing, so let's not use it. |
||||
rm -rf bldnat/ bldcross/ |
||||
|
||||
if false; then |
||||
printf '\n\n ---- native ---- \n\n' |
||||
do_bld bldnat |
||||
ninja -j1 -v -C bldnat print_link_nativetrue |
||||
ninja -j1 -v -C bldnat print_link_nativenone |
||||
ninja -j1 -v -C bldnat print_link_nativefalse |
||||
fi |
||||
|
||||
# One --cross-file |
||||
if true; then |
||||
printf '\n\n ---- cross ----- \n\n' |
||||
do_bld bldcross --cross-file=cross-clang.ini |
||||
# ninja -j1 -v -C bldcross print_link_nativetrue |
||||
# ninja -j1 -v -C bldcross print_link_nativenone |
||||
ninja -j1 -v -C bldcross print_link_nativefalse |
||||
fi |
||||
|
||||
} |
||||
|
||||
main "$@" |
@ -0,0 +1,21 @@ |
||||
[binaries] |
||||
# We assume gcc is the default. clang is conviently different yet |
||||
# cloning most of gcc's user interface. Same for ld.gold. |
||||
c = 'clang' |
||||
ld = 'ld.gold' |
||||
strip = 'strip' |
||||
|
||||
[properties] |
||||
cpp_args = ['-Dcross_file_CPP_args=___YES_crossfile___'] |
||||
c_args = ['-Dcross_file_C_args=___YES_crossfile___'] |
||||
c_link_args = ['-Wl,--undefined=cross_file_C_link_args'] |
||||
|
||||
[host_machine] |
||||
# Use "windows" to avoid "fallback to |
||||
# native" issue(s) like https://github.com/mesonbuild/meson/issues/5102 |
||||
# A "bare metal" option would be nice |
||||
# https://github.com/mesonbuild/meson/issues/6063 |
||||
system = 'windows' |
||||
cpu_family = 'x86' |
||||
cpu = 'i586' |
||||
endian = 'little' |
@ -0,0 +1,103 @@ |
||||
|
||||
project('c_args test', 'c', |
||||
default_options: [ |
||||
|
||||
'build.cpp_args=-Dproject_default_options_buildm_CPP_args=___YES_project_defaults__', |
||||
'build.c_args=-Dproject_default_options_buildm_C_args=___YES_project_defaults__', |
||||
'build.c_link_args=-Wl,--undefined=project_default_options_buildm_C_link_args', |
||||
|
||||
'cpp_args=-Dproject_default_options_CPP_args=___YES_project_defaults__', |
||||
'c_args=-Dproject_default_options_C_args=___YES_project_defaults__', |
||||
'c_link_args=-Wl,--undefined=project_default_options_C_link_args', |
||||
|
||||
] |
||||
) |
||||
|
||||
|
||||
# These also take native:true/false. The default value is: "!is_cross_build()" |
||||
add_global_arguments('-Dadd_global_args=___YES_add_global_args____', language : 'c') |
||||
|
||||
add_project_arguments('-Dadd_project_args=___YES_add_project_args___', language : 'c') |
||||
|
||||
|
||||
YES_SIR = '___YES_executable_nativetrue___' |
||||
exe_true = executable('test_nativetrue.exe', 'test_params.c', native:true, |
||||
|
||||
# Never overriden? |
||||
cpp_args : '-Dexecutable_CPP_args=' + YES_SIR, |
||||
c_args : '-Dexecutable_C_args=' + YES_SIR, |
||||
link_args : '-Wl,--undefined=executable_nativetrue_C_link_args', |
||||
|
||||
) |
||||
run_target('print_link_nativetrue', |
||||
command : [ 'nm', '--undefined-only', exe_true ], |
||||
) |
||||
|
||||
|
||||
YES_SIR = '___YES_executable_nativenone___' |
||||
exe_none = executable('test_nativenone.exe', 'test_params.c', # native: none |
||||
|
||||
cpp_args : '-Dexecutable_CPP_args=' + YES_SIR, |
||||
c_args : '-Dexecutable_C_args=' + YES_SIR, |
||||
link_args : '-Wl,--undefined=executable_nativenone_C_link_args', |
||||
) |
||||
run_target('print_link_nativenone', |
||||
command : [ 'nm', '--undefined-only', exe_none ] |
||||
) |
||||
|
||||
|
||||
YES_SIR = '___YES_executable_nativefalse___' |
||||
exe_false = executable('test_nativefalse.exe', 'test_params.c', native:false, |
||||
|
||||
cpp_args : '-Dexecutable_CPP_args=' + YES_SIR, |
||||
c_args : '-Dexecutable_C_args=' + YES_SIR, |
||||
link_args : '-Wl,--undefined=executable_nativefalse_C_link_args', |
||||
) |
||||
run_target('print_link_nativefalse', |
||||
command : [ 'nm', '--undefined-only', exe_false ], |
||||
) |
||||
|
||||
|
||||
|
||||
|
||||
# To not look ugly, \n and \t need this workaround: |
||||
# https://github.com/mesonbuild/meson/pull/6241 |
||||
run_target('print_flags', |
||||
command : [ |
||||
'printf', |
||||
|
||||
# '''\n\nget_option(cpp_args)\t=\t[%s]\n''' + |
||||
'get_option(c_args)\\t=\\t[%s]\\n' + |
||||
'get_option(c_link_args)\\t=\\t[%s]\\n' + |
||||
|
||||
# '''get_option(build.cpp_args)\t=\t[%s]\n''' + |
||||
'''get_option(build.c_args)\t=\t[%s]\n''' + |
||||
'get_option(build.c_link_args)\\t=\\t[%s]\\n' + |
||||
|
||||
'meson.get_cross_property(cpp_args, <empty>)\\t=\\t[%s]\\n' + |
||||
'meson.get_cross_property(c_args, <empty>)\\t=\\t[%s]\\n' + |
||||
'meson.get_cross_property(c_link_args, <empty>)\\t=\\t[%s]\\n' + |
||||
'meson.get_cross_property(fubar, <empty>)\\t=\\t[%s]\\n', |
||||
|
||||
# ','.join(get_option('cpp_args')), |
||||
','.join(get_option('c_args')), |
||||
','.join(get_option('c_link_args')), |
||||
|
||||
# ','.join(get_option('build.cpp_args')), |
||||
','.join(get_option('build.c_args')), |
||||
','.join(get_option('build.c_link_args')), |
||||
|
||||
# Unlike get_option(), .get_cross_property() is free-form. |
||||
|
||||
','.join(meson.get_cross_property('cpp_args', |
||||
['<EMPTY>'])), |
||||
','.join(meson.get_cross_property('c_args', |
||||
['<EMPTY>'])), |
||||
','.join(meson.get_cross_property('c_link_args', |
||||
['<EMPTY>'])), |
||||
','.join(meson.get_cross_property('fubar', |
||||
['<EMPTY>'])), |
||||
|
||||
] |
||||
) |
||||
|
@ -0,0 +1,53 @@ |
||||
|
||||
// This code logs preprocessor values.
|
||||
|
||||
// It would be trivial to change this and assert() them in some
|
||||
// automated test(s) instead.
|
||||
|
||||
|
||||
#define QUOTE(unquoted) #unquoted |
||||
// QUOTE either "arg" iself, or its expansion if any.
|
||||
#define stringify_value(arg) QUOTE(arg) |
||||
|
||||
// As usual, undefined macros "expand to themselves".
|
||||
#define name_value(arg) #arg "\texpands to ->\t" stringify_value(arg) |
||||
|
||||
// clang makes #pragma message output look like a warning but -Werror
|
||||
// doesn't actually fail
|
||||
|
||||
#if 1 |
||||
// executable( c_args: ) never overwrites, always appends?
|
||||
#pragma message name_value(executable_CPP_args) |
||||
#pragma message name_value(executable_C_args) |
||||
#endif |
||||
|
||||
// In tentative partial order: if defined in two places AND they are
|
||||
// mutually exclusive, then the first one should win.
|
||||
|
||||
#if 1 |
||||
#pragma message name_value(CLIsetup_buildm_CPP_args) |
||||
#pragma message name_value(CLIsetup_buildm_C_args) |
||||
#pragma message name_value(CLIsetup_CPP_args) |
||||
#pragma message name_value(CLIsetup_C_args) |
||||
|
||||
#pragma message name_value(project_default_options_buildm_CPP_args) |
||||
#pragma message name_value(project_default_options_buildm_C_args) |
||||
#pragma message name_value(project_default_options_CPP_args) |
||||
#pragma message name_value(project_default_options_C_args) |
||||
|
||||
#pragma message name_value(env_CPPFLAGS) |
||||
#pragma message name_value(env_CFLAGS) |
||||
|
||||
#pragma message name_value(cross_file_CPP_args) |
||||
#pragma message name_value(cross_file_C_args) |
||||
|
||||
#pragma message name_value(add_global_args) |
||||
#pragma message name_value(add_project_args) |
||||
|
||||
#endif |
||||
|
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
return 0; |
||||
} |
Loading…
Reference in new issue