Open dcbaker opened 4 years ago
Which features are those? IIRC the name-prefixed versions have (most of) the settings already so specifying objcopy in your cross file's executable section makes find_program('objcopy')
work without additional setup (granted by usage of it has been fairly simple).
in particular the --binary-architecture
and --output
arguments to objcopy. Having to have logic to figure out what goes there for each supported architecture is a pain. being able to just have something like:
o = binutils.objcopy(
output : 'foo.o',
input : 'input.file',
target : 'host' | 'build' # target?
args : ['some', 'other' args'],
)
would be much nicer than what I have now, which is:
if host_machine.system() == 'linux' # TODO: solaris, bsd, etc
if host_machine.cpu_family() == 'x86_64'
b_arch = 'i386:x86_64'
b_type = 'elf64-x86-64'
elif host_machine.cpu_fmaily() == 'x86'
b_arch = 'i386'
b_type = 'elf32-i386'
endif
endif
# TODO: all the other things
p = find_program('objcopy')
o = custom_target(
...
command : [
p, '--input', 'binary', '--output', b_type, '--binary-architecture', b_arch, '@INPUT@', '@OUTPUT@'
]
)
At least on my system there is no i686-linux-gnu-objcopy
, in fact, the only "cross" objcopy's I have are mingw ones, even my arm toolchains don't have their own objcopy, just the x86_64-linux-gnu one.
Would there be some way to specify the binutils, like llvm vs. gnu?
For comparison, Debian does have an i686-linux-gnu-objcopy
.
I believe Meson doesn't let the user invoke the assembler or the linker directly, correct? The only two options are
[binaries].c -Wl,--script ... -Wl,--etc ...
), orcustom_target( command: "ld <flags>...", )
Meson is still relatively new to me, sorry if I missed something here.
While C and C++ are highly portable languages, assembly and linker code are very far from it (and will probably never be). Consider the EDK2 project for instance: it supports a large and diverse set of operating systems and toolchains. However for x86 assembly it supports only one assembler, which I think rules out option 1.
So I hope this "Add a binutils module" issue #6063 is among others about adding new (and of course optional) as
and ld
fields in cross files and corresponding logic behind them. Is it?
https://mesonbuild.com/Cross-compilation.html#defining-the-environment
You can already do that. The binaries entry overrides all lookups via find_program
, not just compilers. If you have a program called flibflob
, you can override that to whatever you want by putting a declaration for flibflob
in your cross file.
You can already do that.
Was this an answer to "Would there be some way to specify the binutils, like llvm vs. gnu" ?
- to step out of Meson and do all the linking "manually" with a custom_target()
This proved easier than I thought, not the least thanks tofake_lib.extract_all_objects()
, see pseudo-code below. This lets me point Meson at a very specific linker [script] without forcing any specific compiler or assembler. Freedom from the (tool)chain!
It's early days but seems to work for now; should I expect any issue or important feature(s) missing because I'm hiding from meson the true linking nature of bare_metal
's generation? Is this a hack and if yes is there any more "mesonic" way to do this?
# This library is not used, this is just a convenient way to
# compile everything in one step.
fake_lib = static_library(...
'1.c', '2.S', ... ,
c_args: [ '-fno-pic', ....]
)
# fake_lib also solves this circular dependency problem \o/
# https://github.com/mesonbuild/meson/pull/6061#issuecomment-547138357
#
# '@' is not allowed in linker scripts;
# search and replace 'fakelib@sta' with 'fakelib?sta'
# https://github.com/mesonbuild/meson/pull/291
lib_dir = '?'.join(fake_lib.get_id().split('@'))
very_not_portable_linker_script = configure_file(...
configuration : { 'OBJSDIR': lib_dir }
)
very_specific_linker = find_program('my-ld')
bare_metal = custom_target(...
input: fake_lib.extract_all_objects(),
# [2019-11-12 comment]
# Ideally, linker scripts should be part of the "input:", however:
# 1. prefixing files("myscript.lds")[n] with '--script=' doesn't seem
# possible: "error: can only concatenate str (not "File") to str"
# 2. prefixing only _some_ of the @INPUTn@ and not the object files
# seems difficult too.
# So let's pretend linker scripts are "depend_files:" not part of the
# "command:" and then sneak them into the command: behind
# meson's back.
depend_files: very_not_portable_linker_script,
command: [ very_specific_linker ] + [ '@INPUT@' ]
+ [ '--script=' + very_not_portable_linker_script ]
+ [ '-o', '@OUTPUT@' ]
...
)
- to rely on the compiler front-end (e.g.: [binaries].c -Wl,--script ... -Wl,--etc ...),
I tried this with XCode 11 (clang v10) and it was a disaster. At first sight -fuse-ld=/my/home/built/linker
seems to work but in fact not because this LLVM instance insists on passing a few macOS-specific options like -macosx_version_min 123
or -lto_library something.dylib
- even when appending and prepending -fno-lto
to the clang command line!
Granted this is just one front-end example, however I suspect most low-level / bare metal development requires invoking the linker directly because of the fine level of control required. I mean I suspect the front-end layer of indirection typically assumes too much and that gets in the way. I'm of course not considering targets that depend on a single, vendor-specific toolchain. Who cares about those :-)
Curious how high is "bare-metal" on the list of Meson requirements/priorities?
Found these:
https://reviews.llvm.org/D25932 "Unconditionally pass -lto_library
to the linker on Darwin"
https://lists.llvm.org/pipermail/llvm-dev/2018-February/121135.html
"[llvm-dev] how to avoid linking with libLTO?"
The clang -mlinker-version=...
workaround suggested at https://lists.llvm.org/pipermail/llvm-dev/2018-January/120215.html does remove a couple ld64-specific flags. Then it just fails on the next ld64 flags
linux/scripts/link-vmlinux.sh
invokes ${LD} directly.
Bare metal is important to us. There are in fact commercial products that ship with firmwares built with Meson (or, at least, this seems very strongly to be the case given certain bugs and discussions I have had with people, but sadly there is no public info I can point people to).
The binaries entry overrides all lookups via find_program, not just compilers. If you have a program called flibflob, you can override that to whatever you want by putting a declaration for flibflob in your cross file.
Thanks! However it's more subtle and took me some time to figure it out. While powerful, I think it's very unusual for a string in any language to be both a symbol and a literal!
# 'ld' is *both* a property name and a literal fallback. find_program()
# gives precedence to whatever is in the last --cross-file that defines
# ld=... When not found, it falls back on searching for 'ld' in the
# PATH. Definitions in other --cross-file earlier on the command line
# are totally ignored.
# https://mesonbuild.com/Reference-manual.html#find_program
my_ld = find_program('ld')
While C and C++ are highly portable languages, linker scripts are very far from it ...
At first sight
-fuse-ld=/my/home/built/linker
seems to work
In theory, -fuse-ld=
allows you to decouple the choice of the linker from the choice of the compiler. After a bit more research and practice, usage of -fuse-ld=
seems rare and most of the time it's only to switch between linkers "close" to each other like bfd
and gold
(which are even part of the same package). That flexibility doesn't seem to get that much testing in practice.
@dcbaker of Add a way to select the dynamic linker
#6207 fame, any "real-world" experience of -fuse-ld=
to share? From what you've seen, how is -fuse-ld=
typically used and what for?
Seems related to Solving the LD issue
#6442
When invoked by clang the linker will do what it thinks is correct. For native macos builds, it has macos things:
# builtin ld
% clang -Wl,--version -v
Apple clang version 14.0.0 (clang-1400.0.29.102)
Target: arm64-apple-darwin21.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
"/Library/Developer/CommandLineTools/usr/bin/ld" -demangle -lto_library /Library/Developer/CommandLineTools/usr/lib/libLTO.dylib -dynamic -arch arm64 -platform_version macos 12.0.0 12.3 -syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -o a.out -L/usr/local/lib --version -lSystem /Library/Developer/CommandLineTools/usr/lib/clang/14.0.0/lib/darwin/libclang_rt.osx.a
ld: unknown option: --version
clang: error: linker command failed with exit code 1 (use -v to see invocation)
# homebrew clang
% /opt/homebrew/opt/llvm/bin/lld
lld is a generic driver.
Invoke ld.lld (Unix), ld64.lld (macOS), lld-link (Windows), wasm-ld (WebAssembly) instead
# homebrew ld.lld for unix builds
% clang -Wl,--version -fuse-ld=/opt/homebrew/opt/llvm/bin/ld.lld -v
Apple clang version 14.0.0 (clang-1400.0.29.102)
Target: arm64-apple-darwin21.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
"/opt/homebrew/opt/llvm/bin/ld.lld" -demangle -lto_library /Library/Developer/CommandLineTools/usr/lib/libLTO.dylib -dynamic -arch arm64 -platform_version macos 12.0.0 12.3 -syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -o a.out -L/usr/local/lib --version -lSystem /Library/Developer/CommandLineTools/usr/lib/clang/14.0.0/lib/darwin/libclang_rt.osx.a
ld.lld: error: unknown argument '-dynamic', did you mean '-Bdynamic'
ld.lld: error: unknown argument '-arch'
ld.lld: error: unknown argument '-platform_version'
ld.lld: error: unknown argument '-syslibroot'
Homebrew LLD 15.0.6 (compatible with GNU linkers)
clang: error: linker command failed with exit code 1 (use -v to see invocation)
For cross builds, it removes the macos things. For example, --target=arm-linux-gnu -mfloat-abi=hard
for 32 bit arm linux target. Which I am exploring here: https://github.com/mesonbuild/wrapdb/issues/830
% clang -Wl,--version -fuse-ld=/opt/homebrew/opt/llvm/bin/ld.lld --target=arm-linux-gnu -mfloat-abi=hard -v
Apple clang version 14.0.0 (clang-1400.0.29.102)
Target: arm-unknown-linux-gnu
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
"/opt/homebrew/opt/llvm/bin/ld.lld" -EL -X --eh-frame-hdr -m armelf_linux_eabi -dynamic-linker /lib/ld-linux-armhf.so.3 -o a.out crt1.o crti.o crtbegin.o -L/usr/lib/../lib -L/Library/Developer/CommandLineTools/usr/bin/../lib -L/usr/lib --version -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed crtend.o crtn.o
Homebrew LLD 15.0.6 (compatible with GNU linkers)
Cheers, Joe
I think having a module for dealing with the tools provided by gnu binutils (and alternate implementations like the llvm ones) would be pretty useful.
In my case I'm using
objcopy
, and being able to have some of the arguments about the host and build machine populated automatically would be pretty handy.There's also #5995, and having some sort of
binutils.configure_linker_script
seems useful.I'm planning to get around to this myself, but there are some other things I need to get to first, including fixing regressions in 0.50. The main purpose of this issue is to collect other ideas that should be added to this module and solicit feedback.