Page 2 of 2

Re: Setting up build environment with Meson

Posted: Wed Mar 10, 2021 2:15 pm
by kzinti
So I was just looking at Meson's code to understand what I could do.

compiler.find_library('libgcc') doesn't actually ask GCC where libgcc is. What it does is ask the compiler for the library search path and then Meson itself walks the path looking for "libgcc.a". This means that C flags are not taken into account and the wrong libgcc is picked up. This is completely broken.

So Meson doesn't support multilib at all.

Meson could pass the C flags to the compiler when asking for the library search paths, but it doesn't appear to do so.

Doing this doesn't work either:

Code: Select all

bootloader = executable('bootloader',
    sources: sources,
    link_args: [
        '-lgcc',
    ],
)
It doesn't work because Meson is smart enough to understand this is a library and then internally uses find_library() to find its path (without considering multilib, of course!).

I am sad. Time to move on from Meson I think.

Re: Setting up build environment with Meson

Posted: Wed Mar 10, 2021 2:36 pm
by kzinti
I suppose a workaround could be to define one cross file per multi-lib set of options. This probably would work around the issue. Hopefully Meson doesn't try to interepret args given to the compiler this way.

So instead of:

Code: Select all

[binaries]
c = 'x86_64-rainbow-elf-gcc'
One could do:

Code: Select all

[binaries]
c = ['x86_64-rainbow-elf-gcc', '-fpic', '-mno-red-zone']
Effectively, each multilib would be handled as a different compiler/toolchain.

Re: Setting up build environment with Meson

Posted: Wed Mar 10, 2021 11:13 pm
by kzinti
I've spent a fair amount of time on this and in the end I will be sticking with plain Makefiles.

I did some benchmarks and found that at the scale my project is right now, a no-change build takes the same time with Ninja and Make. A build from scratch is actually slower with Meson because it needs to generate the build files and it's all implemented in python. This seems to be consistent with benchmarks available on the Internet.

The complexity of my Makefiles and Meson build files are about the same. But Makefiles are one less dependency and far more flexible.

Here are some of the meson files I built for posterity and anyone looking in to Meson in the future. Note: this doesn't address the crti/crtn/crtbegin/crtend link order, see posts above for a possible solution using a link script.

Cross-file for EFI bootloader:

Code: Select all

[binaries]
c = ['x86_64-rainbow-elf-gcc', '-fpic', '-mno-red-zone']
cpp = ['x86_64-rainbow-elf-gcc', '-fpic', '-mno-red-zone']
ar = 'x86_64-rainbow-elf-ar'
objcopy = 'x86_64-rainbow-elf-objcopy'
strip = 'x86_64-rainbow-elf-strip'

[host_machine]
system = 'rainbow'
cpu_family = 'x86'
cpu = 'x86_64'
endian = 'little'

[built-in options]
cpp_eh='none'
cpp_rtti=false
cpp_link_args=[
    '-shared',
    '-Bsymbolic',
    '-Wl,-pie'
    ]
Main meson.build file:

Code: Select all

project('boot', ['c', 'cpp'], version : '1.0')

objcopy = find_program('objcopy')

add_project_arguments('-ffreestanding', '-fbuiltin', '-mgeneral-regs-only', language: ['c', 'cpp'])
add_project_link_arguments('-nostdlib', '-z', 'noexecstack', language: ['c', 'cpp'])

includes = [
    '../include',
    '../third_party',
    ...
]

sources = files(
    'boot.cpp',
    'display.cpp',
    'memory.cpp',
    ...
)

link_script = 'efi.lds'

cpp = meson.get_compiler('cpp')
libgcc = cpp.find_library('libgcc')
crtbegin = run_command(cpp, '-print-file-name=crtbegin.o').stdout().strip()
crtend = run_command(cpp, '-print-file-name=crtend.o').stdout().strip()

libs = [
    libgcc,
]

bootloader = executable('bootloader',
    sources: sources,
    objects: [crtbegin, crtend],
    include_directories: includes,
    dependencies: libs,
    link_args: [
        '-T' + meson.source_root() / link_script,
    ],
    link_depends: link_script,
)

custom_target(
    'bootloader.efi',
    input: bootloader,
    output: 'boot.efi',
    command: [ objcopy,
        '-j', '.text',
        '-j', '.rodata',
        '-j', '.data',
        '-j', '.dynamic',
        '-j', '.dynsym',
        '-j', '.rel.*',
        '-j', '.rela.*',
        '-j', '.reloc',
        '--target', 'efi-app-x86_64',
        '@INPUT@',
        '@OUTPUT@'
    ],
    build_by_default: true,
)