What is the meson equivalent of cmake's `FetchContent`? - cmake

How would I fetch a dependency from GitHub in meson? I am trying to convert the following cmake snippet into meson
FetchContent_Declare(
some_dep
GIT_REPOSITORY https://github.com/some/repo
GIT_TAG sometag
SOURCE_SUBDIR src
)
FetchContent_MakeAvailable(some_dep)
Note that this dependency may not be using meson as its build system.

The meson equivalent is subprojects and the wrap dependency system. Here a simple example:
subprojects/fmt.wrap:
[wrap-file]
directory = fmt-7.1.3
source_url = https://github.com/fmtlib/fmt/archive/7.1.3.tar.gz
source_filename = fmt-7.1.3.tar.gz
source_hash = 5cae7072042b3043e12d53d50ef404bbb76949dad1de368d7f993a15c8c05ecc
patch_url = https://wrapdb.mesonbuild.com/v1/projects/fmt/7.1.3/1/get_zip
patch_filename = fmt-7.1.3-1-wrap.zip
patch_hash = 6eb951a51806fd6ffd596064825c39b844c1fe1799840ef507b61a53dba08213
[provide]
fmt = fmt_dep
It is a meson convention that the directory must be named subprojects and be a top-level directory.
meson.build:
project('demo', 'cpp')
fmt_dep = dependency('fmt-7', required: false)
if not fmt_dep.found()
fmt_proj = subproject('fmt')
fmt_dep = fmt_proj.get_variable('fmt_dep')
endif
executable('demo', 'main.cpp', dependencies: fmt_dep, install: true)
main.cpp:
#include <fmt/core.h>
int main() {
fmt::print("Hello, world!\n");
}
This will search libfmt on your system and fallback to downloading it as specified in the wrap file. The subproject() function requires a meson.build file in the root directory, similar to how FetchContent expects a CMakeLists.txt. If the respective project does not have meson build files, you can provide patches through the patch_* or diff_files properties in the wrap file. This is e.g. the case for libfmt does not have meson build files. You can also use [wrap-git] instead of [wrap-file] to specify a git repository instead of a release tarball. Please refer to the documentation.
Tip: The meson developers maintain the Wrap DB, where you can find wrap files for some common libraries/projects.

Related

google test and wrap file meson

Hi in my project I need to use google test and I use the
gtest.wrap file in order to download the gtest with the patch for meson
[wrap-file]
directory = googletest
source_url = https://github.com/google/googletest/archive/release-1.11.0.tar.gz
source_filename = gtest-1.11.0.tar.gz
source_hash = b4870bf121ff7795ba20d20bcdd8627b8e088f2d1dab299a031c1034eddc93d5
patch_filename = gtest_1.11.0-2_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/gtest_1.11.0-2/get_patch
patch_hash = 764530d812ac161c9eab02a8cfaec67c871fcfc5548e29fd3d488070913d4e94
[provide]
gtest = gtest_dep
gtest_main = gtest_main_dep
gmock = gmock_dep
gmock_main = gmock_main_dep
but when i insert in the meson.build the call to gtest wrap
gtest_proj = subproject('gtest')
the getst is cloned correctly but in the meson configuration I got the following error
..../meson.build:64:2: ERROR: Subproject exists but has no meson.build file
that is referred to the line where i call the dependency to gtest
The googletest is CMake based project and thus try to import it with cmake module:
cmake = import('cmake')
gtest_proj = cmake.subproject('gtest')
You can also check this implementation on how to build with own flags and declare dependency.

How to force meson to use only wrap subproject

I have a few subprojects defined in wrap files in the subprojects directory and declared in the meson.build file. Unfortunately I am forced to have some of the subprojects installed on my host system. Meson by default checks if a subproject is installed in the host os filesystem then eventually downloads and builds the subproject if it is unavailable. How to force meson to not use system libraries/headers but to always download/build subprojects independently in own build directory and link it during compilation?
subprojects/xyz.wrap:
[wrap-git]
url = https://github.com/bar/xyz.git
revision = HEAD
[provide]
xyz = xyz_dep
meson.build:
xyz = dependency('xyz')
...
deps = [
...
xyz
...
]
executable(foo, dependencies: deps)
You can force a dependency to fallback to its local subprojects version using --force-fallback-for=<dependency_name> during meson setup ....
For example, I have SDL2 installed as a system package, but I can use the WrapDB version with the following command:
meson setup build --force-fallback-for=sdl2
Reference:
https://github.com/mesonbuild/meson/issues/7218
You can also force fallback of all dependencies with -Dwrap_mode=forcefallback.
See meson options : https://mesonbuild.com/Builtin-options.html#core-options

Overwrite subdirectory's variable CMAKE_BINARY_DIR

I use Googletest library as a git submodule and I would like to move its build artifacts in a designated folder, however inside of googletest/CMakeLists.txt (that I would like to avoid changing) it hardcodes artifacts path to
${CMAKE_BUILD_DIR}/lib
and unfortunately maintainers didn't use ${CMAKE_CURRENT_BUILD_DIR} instead to add their artifacts in their local build path that I specify using add_subdirectory command in my own CMakeLists.txt:
add_subdirectory(${VENDOR_SOURCE_DIR}/googletest ${VENDOR_BINARY_DIR}/googletest)
Some artifacts respect the second path, but those hardcoded with aforementioned line don't.
Is there a way to overwrite Googletest's local value of ${CMAKE_BUILD_DIR} without forking/modifying the library's CMakeLists.txt?
You can set dir on gtest target:
function target_set_dir(target dir)
set_target_properties(${target} PROPERTIES
CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${dir}
CMAKE_LIBRARY_OUTPUT_DIRECTORY ${dir}
CMAKE_RUNTIME_OUTPUT_DIRECTORY ${dir}
)
endfunction()
target_set_dir(gtest ${CMAKE_BUILD_DIR]/gtest})

How can I specify library path when using Meson?

I'm trying to build a c++ project with Meson.
The thing is, I have some libraries under /opt/conda
but can't figure out how to link the project when running meson build.
It seems to be only searching through /usr/lib directory.
As far as I understood, meson uses cmake and pkg-config to look for libraries.
Then would setting something like CMAKE_PREFIX_PATH be a feasible solution? and if so, how can I do that?
Thanks in advance.
I see two possible approaches to solve your problem.
the first solution uses LIBRARY_PATH, which is different from LD_LIBRARY_PATH as explained later.
the second solution uses a modified meson file to directly pass options to the linker. Optionally, it also uses rpath that eliminates the need to modify LD_LIBRARY_PATH afterward.
First solution
When building your project the linker use LIBRARY_PATH (and not LD_LIBRARY_PATH)
LIBRARY_PATH is used by gcc before compilation to search directories
containing static and shared libraries that need to be linked to your
program.
LD_LIBRARY_PATH is used by your program to search directories
containing shared libraries after it has been successfully compiled
and linked.
further details: LD_LIBRARY_PATH vs LIBRARY_PATH
Maybe you can try
export LIBRARY_PATH=/opt/conda/:$LIBRARY_PATH
before running meson to build your project.
Second solution
Modifying your meson file and use rpath (optional)
An alternative to the previous first solution is to directly modify your Meson file to pass some options to the linker.
Here is something I used in the past you can easily adapt to your problem:
#
# blaspp
#
blaspp_lib = 'blaspp'
blaspp_lib_dir = '/opt/slate/lib'
blaspp_header_dir = '/opt/slate/include'
blaspp_dep = declare_dependency(
link_args : ['-L' + blaspp_lib_dir, '-l' + blaspp_lib],
include_directories : include_directories(blaspp_header_dir))
executable('test_blaspp',
'test_blaspp.cpp',
build_rpath : blaspp_lib_dir,
install_rpath : blaspp_lib_dir,
dependencies : [blaspp_dep])
declare_dependency(...) defines options to pass to the linker (this replaces the need to define LIBRARY_PATH in the first solution)
executable(...) defines rpath. This is an optional step that embeds the extra library path information directly into the executable. If you use this, you will not have to modify the LD_LIBRARY_PATH when running your executable.
Further details: https://amir.rachum.com/blog/2016/09/17/shared-libraries/ (have a look at the "rpath and runpath" section) and see wikipedia: https://en.wikipedia.org/wiki/Rpath
If I understand the documentation correctly, you could use different / others build system as subproject, and it doesn't seem basing on cmake.
You should be able to define CMAKE_PREFIX_PATH in a CMakeList.txt of a cmake project, and access the generated library within meson context:
in your cmake subproject:
add_library(cm_lib SHARED ${SOURCES})
in your meson:
cmake = import('cmake')
# Configure the CMake project
sub_proj = cmake.subproject('libsimple_cmake')
# Fetch the dependency object
cm_lib = sub_proj.dependency('cm_lib')
executable(exe1, ['sources'], dependencies: [cm_lib])
if you only want to propagate any specific library to meson, than it looks like you'll need to bundle those third party library, or using built-in options.
But first of all: Have you check, either /opt/conda is in your LD_LIBRARY_PATH ?
Surprised no one mentioned it but this is how it is done from within meson.
CXX = meson.get_compiler('cpp')
libs_you_need_to_link = ['lib_a', 'lib_b', 'lib_c']
deps = []
foreach lib_name : libs_you_need_to_link
deps += CXX.find_library(lib_name, dirs : ['/opt/conda', '/other/path'])
endforeach

Meson: how to make find_library() works with an unusual path?

For my Meson project I have a dependency that is in an "unusual" place:
/opt/MyDependence/lib/libmyLib.so
/opt/MyDependence/include/myLib.hpp
My meson file is:
project('Test', ['cpp'])
cpp = meson.get_compiler('cpp')
myLib_dep = cpp.find_library('myLib', required: true)
Obviously Meson cannot find the library
Meson.build:5:0: ERROR: C++ library 'myLib' not found
The problem is that I do not know the "canonical" way to add extra search paths so that Meson can found my lib. Any idea?
update: please note that even if I use:
meson --libdir=/opt/MyDepedence/lib build
I get this error message:
meson.build:1:0: ERROR: The value of the 'libdir' option is '/opt/MyDepedence/lib' which must be a subdir of the prefix '/usr/local'.
Note that if you pass a relative path, it is assumed to be a subdir of prefix.
find_library now has an optional argument dirs (since 0.53.0) that indicates an extra list of absolute paths where to look for program names.
cpp = meson.get_compiler('cpp')
myLib_dep = cpp.find_library('myLib', dirs: '/opt/MyDepedence/lib', required: true)
I finally got a solution, one must use LIBRARY_PATH
export LIBRARY_PATH=/opt/MyDepedence/lib
meson build
Note: attention this is not LD_LIBRARY_PATH, see there for the difference
Also read this Meson/issues/217 . For Windows, the LIBRARY_PATH equivalent seems to be LIBPATH (but I was not able to check as I only run under Linux).
An alternative is to "manually" define a new dependence. In your Meson project:
project('Test, ['cpp'])
myLib_dep = declare_dependency(link_args : ['-L/opt/MyDependence/lib', '-lmyLib'],
include_directories : ['/opt/MyDependence/include'])
exe1 = executable('main', ['main.cpp'], dependencies : [myLib_dep])
A refinement that could be done is to store this "manual" setting into meson_options.txt.
Note: I finally answered my question, but I am still open to better solutions.
Standard way to solve this is to use pkg-config. In short, library installation procedure should include stage where special "mylib.pc" file is generated (from scratch, or typically from template "mylib.pc.in" - search in the internet, there are lots of examples). Then these small key-value files which has info on include/library dirs, dependencies, etc are installed to some known location, typically /usr/lib/pkgconfig/. Meson naturally runs pkg-config under the hood and finds your library when you have something like this
mylib_dep = dependency('mylib', required: true)
in your meson.build.
Update
Regarding libdir meson option error, you can try add option prefix as well:
meson --prefix=/opt/MyDepedence --libdir=lib build
Note also that with this command line you actually call implicitly setup command (there is no command build, since you will build with ninja) and build is a build directory that will be created using your options. Check this. That is why it is more visible to write:
meson setup build_dir --prefix=/opt/MyDepedence --libdir=lib