Setting up build environment with Meson

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
kzinti
Member
Member
Posts: 898
Joined: Mon Feb 02, 2015 7:11 pm

Re: Setting up build environment with Meson

Post 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.
kzinti
Member
Member
Posts: 898
Joined: Mon Feb 02, 2015 7:11 pm

Re: Setting up build environment with Meson

Post 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.
kzinti
Member
Member
Posts: 898
Joined: Mon Feb 02, 2015 7:11 pm

Re: Setting up build environment with Meson

Post 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,
)
Post Reply