Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[bug] Meson lacking native file during cross compiling #15878

Closed
H2NCH2COOH opened this issue Mar 15, 2024 · 23 comments · Fixed by #15895 or #15919
Closed

[bug] Meson lacking native file during cross compiling #15878

H2NCH2COOH opened this issue Mar 15, 2024 · 23 comments · Fixed by #15895 or #15919
Assignees
Milestone

Comments

@H2NCH2COOH
Copy link

Describe the bug

When cross compiling with Meson, Conan will generate a cross file which works fine.
However, if the project requires native binaries during cross compiling (e.g. an internal tool), we need to also supply a native file to Meson during setup.

How to reproduce it

Download fribidi from conan-center-index and cross build version 1.0.13 on a x86_64 Linux for armv8 Linux.

Saving the conan generated files during a native build and cross build, and manually calling Meson with both the files will succeed.

@franramirez688
Copy link
Contributor

franramirez688 commented Mar 15, 2024

Hi @H2NCH2COOH

I did not get to reproduce your issue, it's working on my side:

$ conan -v
Conan version 2.1.0

$ conan create . --version 1.0.13 -s arch=armv8
.......

======== Input profiles ========
Profile host:
[settings]
arch=armv8
build_type=Release
compiler=gcc
compiler.cppstd=gnu17
compiler.libcxx=libstdc++11
compiler.version=11
os=Linux

Profile build:
[settings]
arch=x86_64
build_type=Release
compiler=gcc
compiler.cppstd=gnu17
compiler.libcxx=libstdc++11
compiler.version=11
os=Linux

........

fribidi/1.0.13: Meson configure cmd: meson setup --cross-file "/root/.conan2/p/b/fribid31355bc001db/b/build-release/conan/conan_meson_cross.ini" "/root/.conan2/p/b/fribid31355bc001db/b/build-release" "/root/.conan2/p/b/fribid31355bc001db/b/src" --prefix=/
fribidi/1.0.13: RUN: meson setup --cross-file "/root/.conan2/p/b/fribid31355bc001db/b/build-release/conan/conan_meson_cross.ini" "/root/.conan2/p/b/fribid31355bc001db/b/build-release" "/root/.conan2/p/b/fribid31355bc001db/b/src" --prefix=/
The Meson build system
Version: 1.2.1
Source dir: /root/.conan2/p/b/fribid31355bc001db/b/src
Build dir: /root/.conan2/p/b/fribid31355bc001db/b/build-release
Build type: cross build
Project name: fribidi
Project version: 1.0.13
C compiler for the host machine: /usr/bin/gcc (gcc 11.1.0 "gcc (Ubuntu 11.1.0-1ubuntu1~20.04) 11.1.0")
C linker for the host machine: /usr/bin/gcc ld.bfd 2.34
C compiler for the build machine: cc (gcc 11.1.0 "cc (Ubuntu 11.1.0-1ubuntu1~20.04) 11.1.0")
C linker for the build machine: cc ld.bfd 2.34
Build machine cpu family: x86_64
Build machine cpu: x86_64
Host machine cpu family: aarch64
Host machine cpu: armv8
Target machine cpu family: aarch64
Target machine cpu: armv8
Compiler for C supports arguments -ansi: YES
Checking for function "memmove" : YES
Checking for function "memset" : YES
Checking for function "strdup" : YES
Has header "stdlib.h" : YES
Has header "string.h" : YES
Has header "memory.h" : YES
Has header "strings.h" : YES
Has header "sys/times.h" : YES
Has header "strings.h" : YES (cached)
Configuring config.h using configuration
Has header "stdlib.h" : YES (cached)
Has header "string.h" : YES (cached)
Has header "strings.h" : YES (cached)
Checking for size of "int" : 4
Configuring fribidi-config.h using configuration
Build targets in project: 15

fribidi 1.0.13

  User defined options
    Cross files: /root/.conan2/p/b/fribid31355bc001db/b/build-release/conan/conan_meson_cross.ini
    prefix     : /

......


fribidi/1.0.13: package(): Packaged 1 file: COPYING
fribidi/1.0.13: package(): Packaged 1 '.a' file: libfribidi.a
fribidi/1.0.13: package(): Packaged 22 '.h' files
fribidi/1.0.13: Created package revision bba885283a016b4748c26769f3e2fd34
fribidi/1.0.13: Package 'e80621978d722fddc470ae5b2514652aec1eb225' created
fribidi/1.0.13: Full package reference: fribidi/1.0.13#f88ca6a20588f5206f56527c0f1c0df5:e80621978d722fddc470ae5b2514652aec1eb225#bba885283a016b4748c26769f3e2fd34
fribidi/1.0.13: Package folder /root/.conan2/p/b/fribid31355bc001db/p

......

fribidi/1.0.13 (test package): RUN: cmake --build "/home/develop/conan-center-index/recipes/fribidi/all/test_package/build/gcc-11-armv8-gnu17-release" -- -j16
Scanning dependencies of target test_package
[ 50%] Building C object CMakeFiles/test_package.dir/test_package.c.o
[100%] Linking C executable test_package
[100%] Built target test_package


======== Testing the package: Executing test ========
fribidi/1.0.13 (test package): Running test()

@H2NCH2COOH
Copy link
Author

Hi @franramirez688,

Thanks for the response.
May I ask if your native compiler is on the default path?

I'm using Conan to create a build system that doesn't rely upon local env so I try to have every executable used during build supplied by Conan (e.g. gcc as a build requirement). So when I faced the problem in this issue, I didn't find a way to supply both the cross compiler and the native compiler to Meson through Conan (I can manually call Meson with both native file and cross file).

@franramirez688
Copy link
Contributor

Hi @H2NCH2COOH

Yes, I'm using a native compiler that is on the default path.

Could you provide your Conan recipe and the profile ones that you're using? I want to reproduce the issue locally.

@H2NCH2COOH
Copy link
Author

Hi @franramirez688 ,

I'm trying to create a sample project using conan-center-index and encountered #14719
The actual env I used involves internal resources that can't be shared.

I'll try to work around the problem.

Thanks for the patience.

@jwillikers
Copy link
Contributor

jwillikers commented Mar 15, 2024

@franramirez688 Without a native file, how does Conan propagate the compiler from the build profile? If you try to use clang as the native compiler on a system where GCC is the default, is this not conveyed to Meson? This situation could be reproduced very easily with a build profile as follows:

[settings]
os=Linux
arch=x86_64
compiler=clang
compiler.version=17
os.libc=gnu
compiler.libcxx=libc++
compiler.cppstd=20

[conf]
tools.build:compiler_executables={"asm": "clang", "c": "clang", "cpp": "clang++"}

Then just build a simple hello world Meson program where executable includes native : true:

main.c:

#include <stdio.h>

int main(int argc, char **argv) {
  printf("Hello there.\n");
  return 0;
}

meson.build:

project('tutorial', 'c')
executable('demo', 'main.c', native : true)

Without a native file, i.e. when a cross file is used exclusively by Conan, then I would expect this to use the default system compiler, i.e. GCC on Linux, to build the program instead of Clang despite using the above Clang profile as the build profile.

@jwillikers
Copy link
Contributor

jwillikers commented Mar 15, 2024

Yup, I can confirm that this doesn't work as expected. Here's a (somewhat) minimal conanfile.py as well.

from conan import ConanFile
from conan.errors import ConanInvalidConfiguration
from conan.tools.apple import fix_apple_shared_install_name
from conan.tools.build import check_min_cppstd
from conan.tools.env import VirtualBuildEnv
from conan.tools.files import apply_conandata_patches, copy, export_conandata_patches, get, replace_in_file, rm, rmdir
from conan.tools.gnu import PkgConfigDeps
from conan.tools.layout import basic_layout
from conan.tools.meson import Meson, MesonToolchain
from conan.tools.microsoft import is_msvc
from conan.tools.scm import Version
import os


required_conan_version = ">=1.53.0"


class PackageConan(ConanFile):
    name = "package"
    description = "short description"
    # Use short name only, conform to SPDX License List: https://spdx.org/licenses/
    # In case not listed there, use "LicenseRef-<license-file-name>"
    license = ""
    url = "https://github.com/conan-io/conan-center-index"
    homepage = "https://github.com/project/package"
    # no "conan" and project name in topics. Use topics from the upstream listed on GH
    topics = ("topic1", "topic2", "topic3")
    # package_type should usually be "library" (if there is shared option)
    package_type = "application"
    settings = "os", "arch", "compiler", "build_type"

    def configure(self):
        self.settings.rm_safe("compiler.cppstd")
        self.settings.rm_safe("compiler.libcxx")

    def layout(self):
        basic_layout(self, src_folder="src")

    def build_requirements(self):
        self.tool_requires("meson/1.3.2")
        if not self.conf.get("tools.gnu:pkg_config", default=False, check_type=str):
            self.tool_requires("pkgconf/2.1.0")

    def source(self):
        get(self, **self.conan_data["sources"][self.version], strip_root=True)

    def generate(self):
        tc = MesonToolchain(self)
        tc.generate()
        tc = PkgConfigDeps(self)
        tc.generate()
        tc = VirtualBuildEnv(self)
        tc.generate()

    def build(self):
        meson = Meson(self)
        meson.configure()
        meson.build()

    def package(self):
        meson = Meson(self)
        meson.install()

And the problem is obvious after running conan install . --profile:build clang --profile:host cross followed by bash -c '. build-debug/conan/conanbuild.sh && meson setup build-debug --cross-file build-debug/conan/conan_meson_cross.ini'. The build-debug/compile_commands.json file shows that the default compiler is still in use:

[
  {
    "directory": "/var/home/jordan/test/build-debug",
    "command": "ccache cc -Idemo.p -I. -I.. -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -O0 -g -MD -MQ demo.p/main.c.o -MF demo.p/main.c.o.d -o demo.p/main.c.o -c ../main.c",
    "file": "../main.c",
    "output": "demo.p/main.c.o"
  }
]

@franramirez688
Copy link
Contributor

Thanks a lot for taking the time to have a minimal example @jwillikers 👏 Indeed, it looks like a bug.
I'll open a branch to perform a reproducible test and fix the issue.

@franramirez688
Copy link
Contributor

franramirez688 commented Mar 20, 2024

Hi @jwillikers @H2NCH2COOH

Finally, there is no bug here. I just added some tests proving that in my PR #15895

The native file is being created, but it's created in the cache, and we did not realize about it. For instance:

$ conan create consumer -pr:h host -pr:b build --build=missing
======== Input profiles ========
Profile host:
[settings]
arch=armv8
build_type=Release
compiler=gcc
compiler.cppstd=gnu17
compiler.libcxx=libstdc++11
compiler.version=11
os=Linux
[conf]
tools.build:compiler_executables={'c': 'gcc', 'cpp': 'g++'}

Profile build:
[settings]
arch=x86_64
compiler=clang
compiler.cppstd=11
compiler.libcxx=libc++
compiler.version=12
os=Linux
[conf]
tools.build:compiler_executables={'c': 'clang', 'cpp': 'clang++'}

...

tool/1.0: Generator 'MesonToolchain' calling 'generate()'
tool/1.0: Generating aggregated env files
tool/1.0: Generated aggregated env files: ['conanbuild.sh', 'conanrun.sh']
tool/1.0: Calling build()
tool/1.0: Package 'd96cd8306a7defac8d0882c3f4f0f0b3782829ed' built
tool/1.0: Build folder /private/var/folders/s8/zgn806y90xq7bdh64hhfw9th0000gr/T/tmp5l25aisbconans/path with spaces/.conan2/p/b/toole1635a5c5d666/b
tool/1.0: Generating the package
tool/1.0: Packaging in folder /private/var/folders/s8/zgn806y90xq7bdh64hhfw9th0000gr/T/tmp5l25aisbconans/path with spaces/.conan2/p/b/toole1635a5c5d666/p
...

The line tool/1.0: Build folder /private/var/folders/s8/zgn806y90xq7bdh64hhfw9th0000gr/T/tmp5l25aisbconans/path with spaces/.conan2/p/b/toole1635a5c5d666/b tells us where Conan generator files are:

$ tree "/private/var/folders/s8/zgn806y90xq7bdh64hhfw9th0000gr/T/tmp5l25aisbconans/path with spaces/.conan2/p/b/toole1635a5c5d666/b"
/private/var/folders/s8/zgn806y90xq7bdh64hhfw9th0000gr/T/tmp5l25aisbconans/path with spaces/.conan2/p/b/toole1635a5c5d666/b
├── conan_meson_native.ini
├── conanbuild.sh
├── conanbuildenv-x86_64.sh
├── conaninfo.txt
├── conanrun.sh
├── conanrunenv-x86_64.sh
├── deactivate_conanbuild.sh
└── deactivate_conanrun.sh

As you can see, there it is our native file using the whole build context.

@jwillikers
Copy link
Contributor

@franramirez688 Is it still generated when running conan install?

@memsharded
Copy link
Member

If the current package is to be built in the build context, because it is a tool-require, and not cross-built, then it is necessary to make it explicit with:

$ conan install . --build-require ...

That should provide a native build for the build context

@H2NCH2COOH
Copy link
Author

The problem is that some projects require building native executable as part of a cross compilation.
This will require Conan passing both a cross file and a native to the meson execution.
It is not that we have two packages one for the host and one for the build.

@memsharded
Copy link
Member

But when there is a dependency of the same package both in build and host context, there are actually 2 different packages for the build and host context. For cross-compilation the binaries won't even be the same. Wouldn't it be the same as documented here: https://docs.conan.io/2/examples/graph/tool_requires/using_protobuf.html?

@franramirez688
Copy link
Contributor

The problem is that some projects require building native executable as part of a cross compilation. This will require Conan passing both a cross file and a native to the meson execution. It is not that we have two packages one for the host and one for the build.

@jwillikers @H2NCH2COOH any simple example to show that would be quite useful to understand that use case.

@jwillikers
Copy link
Contributor

But when there is a dependency of the same package both in build and host context, there are actually 2 different packages for the build and host context. For cross-compilation the binaries won't even be the same. Wouldn't it be the same as documented here: https://docs.conan.io/2/examples/graph/tool_requires/using_protobuf.html?

Ah, that's not wrong. I think the confusion is around use-cases where a package may compile a "helper" utility for the native machine that is used to generate source code or something, kind of like wayland-scanner. Unlike wayland-scanner which is part of the Conan package, there may be situations where this native tool is not actually part of the resultant Conan package. In this situation, it would seem the most sensible to follow the build profile settings from Conan, especially for reproducibility.

It's also worth mentioning the situation where a consumer is using Conan to manage dependencies but not to package their application. In such a case, the consumer may want to build native executables as part of their project and assuming they are cross-compiling, a generated native file from Conan would be useful.

@jwillikers
Copy link
Contributor

The problem is that some projects require building native executable as part of a cross compilation. This will require Conan passing both a cross file and a native to the meson execution. It is not that we have two packages one for the host and one for the build.

@jwillikers @H2NCH2COOH any simple example to show that would be quite useful to understand that use case.

@franramirez688 Glancing at a few projects, I haven't seen this yet. Unfortunately, that doesn't mean there aren't projects out there, possible in CCI, already using this functionality. If I find one, I'll let you know.

Despite not having an example, I think that using a native-file even when cross-compiling may still be valuable for reproducibility.

@franramirez688
Copy link
Contributor

Despite not having an example, I think that using a native-file even when cross-compiling may still be valuable for reproducibility.

Yeah, but it's not a simple task to do that. If we create a Meson native file in this case, should we also create those "native" toolchain files for the rest of Conan toolchains when cross-compiling? That's why I'd want to see a real example to check that use case and if it makes sense to figure out how to solve it with Conan and likely all its toolchains.

@H2NCH2COOH
Copy link
Author

The problem is that some projects require building native executable as part of a cross compilation. This will require Conan passing both a cross file and a native to the meson execution. It is not that we have two packages one for the host and one for the build.

@jwillikers @H2NCH2COOH any simple example to show that would be quite useful to understand that use case.

For example: https://github.com/fribidi/fribidi/blob/b54871c339dabb7434718da3fed2fa63320997e5/gen.tab/meson.build#L72
Here, fribidi asks meson to build an executable for the native machine and use it to generate files.
Alongside with the above meson.build, here is the counter part in automake: https://github.com/fribidi/fribidi/blob/b54871c339dabb7434718da3fed2fa63320997e5/gen.tab/Makefile.am#L27
Doing the same thing by using CC_FOR_BUILD to replace the default CC and build executable for native machine.

@jwillikers
Copy link
Contributor

@franramirez688 @memsharded Can this be re-opened? I think it was closed by accident when that PR was merged. The real example provided above should keep this moving forward.

@franramirez688
Copy link
Contributor

@H2NCH2COOH Thanks for that example. I think it's clear now 😁

I will open another PR to add this mechanism to MesonToolchain.

Thanks for your patience @H2NCH2COOH @jwillikers

@memsharded
Copy link
Member

I think this is related #15486

@jwillikers
Copy link
Contributor

@franramirez688 I just encountered a related issue. When cross-compiling with Meson, pkg-config is specified in the cross file. I think it is only used to find dependencies in the host context if it is specified here and not the native context. I think it may be important to specify pkg-config in native files.

Here's some output from the libva Conan package when I attempt to cross-compile, using Meson 1.4.0. pkgconf is a tool_requires in this case.

Build machine cpu: x86_64
Host machine cpu family: aarch64
Host machine cpu: armv8
Target machine cpu family: aarch64
Target machine cpu: armv8
Library dl found: YES
Found pkg-config: YES (/home/jordan/.conan2/p/b/pkgcof3443d9288354/p/bin/pkgconf) 2.1.0
Run-time dependency libdrm found: YES 2.4.119
Run-time dependency wayland-client found: YES 1.22.0
Did not find pkg-config by name 'pkg-config'
Found pkg-config: NO
Found CMake: /usr/local/bin/cmake (3.28.20240202)
Build-time dependency wayland-scanner found: NO (tried cmake)

../src/meson.build:118:24: ERROR: Dependency lookup for wayland-scanner with method 'pkgconfig' failed: Pkg-config for machine build machine not found. Giving up.

Here it finds the pkgconf specified in the cross file and uses it to find libdrm and wayland-client in the host context. However, when it attempts to find wayland-scanner in the build/native context, it doesn't even find pkg-config at all.

@franramirez688
Copy link
Contributor

For the record, we came up with this solution:

    def generate(self):
        tc = MesonToolchain(self)
        tc.generate()
        # Forcing to create the native context too
        if cross_building(self):
            tc = MesonToolchain(self, native=True)
            tc.generate()

Then, this generate function will create both contexts and the Meson build helper will automatically use both files.

@franramirez688 I just encountered a related issue. When cross-compiling with Meson, pkg-config is specified in the cross file. I think it is only used to find dependencies in the host context if it is specified here and not the native context. I think it may be important to specify pkg-config in native files.

@jwillikers When is this happening? Running the test_package? I have normally solved this one by defining the tools.gnu:pkg_config conf variable or adding this as it's done in multiple recipes (also in the test_package one):

    def build_requirements(self):
        if not self.conf.get("tools.gnu:pkg_config", default=False, check_type=str):
            self.tool_requires("pkgconf/2.1.0")

@jwillikers
Copy link
Contributor

@franramirez688 That's when building the libva library itself, the recipe in CCI, which uses that idiom already. If pkg-config / pkgconf is not installed on the system, then the build fails when cross-compiling because it can't find the pkg-config executable for the build system when locating wayland-scanner in the build context. This is because the pkgconfig Meson variable needs to be set in a native file in order for Meson to know where to find the pkg-config executable from the pkgconf Conan package when looking for native pkg-config files.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment