google test and wrap file meson - googletest

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.

Related

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

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.

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

How to link with a library built using Meson custom_target()?

I'm using Meson custom_target() to build a 3rd party foobar library:
foobar_ct = custom_target('foobar_build',
command: `script.sh`,
output: 'foobar.a')
The custom target calls my script, which in turn calls Make to use existing Makefiles to build the lib. The custom_target() is used as a subproject, and the resulting output file ends up located at ./subprojects/foobar/foobar.a.
When I try to link with it
foobar_dep = dependency('foobar', fallback:...)
exe = executable(
'test',
'main.c',
dependencies: [foobar_dep]
...)
Meson gives me error:
builddir/subprojects/foobar/foobar.a: No such file or directory
How would I link with the foobar.a? Meson expects it at the build directory ./builddir/subprojects/foobar/foobar.a - would it be a proper solution just to add a copy step to my script which would copy foobar.a from the place where Make built it, into the builddir?

Setting up Vulkan, glfw and spdlog correctly using CMake and conan package manager

I'm working on a renderer for Vulkan API. I have big trouble setting up the project correctly using CMake and conan package manager. Let's take a look at my conanfile.py for dependency setup:
from conans import ConanFile, CMake
class InexorConan(ConanFile):
settings = (
"os",
"compiler",
"build_type",
"arch"
)
requires = (
"benchmark/1.5.0",
"glm/0.9.9.7",
"gtest/1.10.0",
"spdlog/1.5.0",
"glfw/3.3.2#bincrafters/stable",
"toml11/3.1.0",
"imgui/1.75",
"assimp/5.0.1",
"enet/1.3.14 "
)
generators = "cmake"
default_options = {
}
def imports(self):
# Copies all dll files from packages bin folder to my "bin" folder (win)
self.copy("*.dll", dst="bin", src="bin")
# Copies all dylib files from packages lib folder to my "lib" folder (macosx)
self.copy("*.dylib*", dst="lib", src="lib") # From lib to lib
# Copies all so files from packages lib folder to my "lib" folder (linux)
self.copy("*.so*", dst="lib", src="lib") # From lib to lib
def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()
All the conan setup is working correctly, as can be seen by CMake output:
Sadly, there is no conan setup for Vulkan API. So I am using some code of Sascha Willem's github repository. My CMake file looks like this:
cmake_minimum_required(VERSION 3.4)
project(inexor-vulkan-renderer)
file(GLOB_RECURSE source_files
"src/*.hpp"
"src/*.cpp"
)
# Use the folder structure in source code directory as project structure in Visual Studio.
function(assign_source_group)
foreach(source_files IN ITEMS ${ARGN})
if (IS_ABSOLUTE "${source_files}")
file(RELATIVE_PATH _source_rel "${CMAKE_CURRENT_SOURCE_DIR}" "${source_files}")
else()
set(_source_rel "${source_files}")
endif()
get_filename_component(_source_path "${_source_rel}" PATH)
string(REPLACE "/" "\\" _source_path_msvc "${_source_path}")
source_group("${_source_path_msvc}" FILES "${source_files}")
endforeach()
endfunction(assign_source_group)
# Use CMake to find Vulkan SDK.
if (NOT CMAKE_VERSION VERSION_LESS 3.7.0)
message(STATUS "Using module to find Vulkan")
find_package(Vulkan)
endif()
# Dependency setup via conan.
# Download conan executer in case it does not exists.
if(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/conan.cmake")
message(STATUS "Downloading conan.cmake from https://github.com/conan-io/cmake-conan")
file(DOWNLOAD "https://raw.githubusercontent.com/conan-io/cmake-conan/v0.14/conan.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/conan.cmake")
endif()
# Execute conan build instructions.
include(${CMAKE_CURRENT_BINARY_DIR}/conan.cmake)
conan_cmake_run(CONANFILE conanfile.py
BASIC_SETUP
BUILD outdated
PROFILE default
PROFILE_AUTO build_type
KEEP_RPATHS
)
# Use the folder structure in source code directory as project structure in Visual Studio.
assign_source_group(${source_files})
add_executable(inexor-vulkan-renderer src/main.cpp ${source_files})
target_link_libraries(inexor-vulkan-renderer PUBLIC ${Vulkan_LIBS} ${CONAN_LIBS})
# Use C++17!
target_compile_features(inexor-vulkan-renderer PRIVATE cxx_std_17)
IF(WIN32)
target_compile_definitions(inexor-vulkan-renderer PRIVATE VK_USE_PLATFORM_WIN32_KHR)
ENDIF()
target_include_directories(inexor-vulkan-renderer PRIVATE Vulkan::Vulkan)
target_link_libraries(inexor-vulkan-renderer Vulkan::Vulkan)
When I generate a Visual Studio project file with this setup, I have to add glfw3.lib, spdlogd.lib and fmtd.lib to the project manually. Other repositories like the official Vulkan samples take a more traditional approachand just paste the libs directly into the repo folders. I don't want to do this since I want conan to work for me. I've been trying to fix this problem for 6 months now.
Why does CMake not link the needed libraries although conan can find them?
Thanks you.
I found the solution: There is a function called conan_target_link_libraries which must be used instead of target_link_libraries. Thanks for the answer.

CMake Fortran Module Directory to be used with add_library

I have a CMake 3.5.2 project that creates a library: libtest.a, which is then linked to by an executable.
The source code is Fortran, and the libtest.a produces a module file: "main.mod"
The executable also needs to include this main.mod file, so to make main.mod accessible, when building the project I set the variable, CMAKE_Fortran_MODULE_DIRECTORY to a known location, and add it to the relevant include paths.
This works great when building the entire project, main.mod is built in a known location, and it is there for whatever code needs it. My usage, however, makes it necessary to only build libtest.a by itself, and leave the executable to be built by a downstream user sometimes.
The issue I am having is that when I go into the libtest source and treat it as its own CMake project, the library will build and install, but the main.mod file is always left in the BINARY_DIR and is not built in the CMAKE_Fortran_MODULE_DIRECTORY, dispite setting in the the CMakeList.txt within libtest.
Is the Fortran_MODULE_DIRECTORY only honored when add_executable() is being called? And just ignored for the library builds alone? Or am I missing something.
Thanks for the help.
EDIT: This will reproduce my issue.
test_mod.f90:
module main
implicit none
real, parameter :: pi=3.2
end module main
tt.f90:
program test
use main
implicit none
real :: a, area
a =10
area = a * 100
end program test
CMakeList.txt:
CMAKE_minimum_required( VERSION 3.5 )
enable_language( Fortran )
project( tt )
file( GLOB test_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.f90 )
add_library( tt STATIC ${test_SOURCES} )
set( CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Mod )
install( TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/Lib/ )
If I build and install the above code, I will get a libtt.a library installed in the Lib directory, however my main.mod will remain in my build directory and is not build in a Mod folder.
Here I assume that the "user" uses cmake to build the project while having access to the source of your project.
The steps to a working build.
There is a CMakeLists.txt file for libtest that specifies CMAKE_Fortran_MODULE_DIRECTORY. This should be enough for main.mod to appear there.
There is a CMakeLists.txt file for buiding the "client" program. This file should include the libtest project with add_subdirectory.
Add target_link_libraries(NAME_OF_PROGRAM NAME_OF_LIBRARY). This only takes care of the linking of libraries and is not sufficient (for solution B below anyway) for the module to be known to the client program.
Now, make your own adventure:
Solution A: in the libtest CMakeLists.txt, place the module where "all modules will go", for instance set(CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/modules) (you need to do this also for the "client" CMakeLists.txt). The variable ${CMAKE_BINARY_DIR} is set by the "client" cmake invocation and will be the same for all included cmake projects. This directory will be listed in the build commands for Fortran programs.
Solution B: in the libtest CMakeLists.txt, place the module of this library in a dedicated directory. You can achieve this, for instance, with set(CMAKE_Fortran_MODULE_DIRECTORY ${PROJECT_BINARY_DIR}/modules). You need then to manually specify this location with include_directories(PATH_THAT_DEPENDS_ON_THE_NAME_OF_THE_SUBPROJECT) in the client CMakeLists.txt.
If you wish the library to be installable, you need to specify paths for installing the library and the module file. With Fortran, you should think of this with the target OS, compiler and architecture in mind.
Links to the CMake documentation:
PROJECT_BINARY_DIR
CMAKE_Fortran_MODULE_DIRECTORY
CMAKE_BINARY_DIR
Following the addition of your sample code, the following modification should do it:
CMAKE_minimum_required( VERSION 3.5 )
enable_language( Fortran )
project( tt )
set( CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Mod )
file( GLOB test_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.f90 )
add_library( tt STATIC ${test_SOURCES} )
install( TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/Lib/ )
install(DIRECTORY ${CMAKE_Fortran_MODULE_DIRECTORY} DESTINATION ${CMAKE_CURRENT_SOURCE_DIR})
Make sure that set( CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Mod ) occurs before any add_library line.
Add install(DIRECTORY ${CMAKE_Fortran_MODULE_DIRECTORY} DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}) to actually install the .mod file. Module files (as header files in C) have to installed in addition to the library file.
The setup you created is a bit unusual in that you locate everything within the source build whereas "usual" install locations are made relative to CMAKE_INSTALL_PREFIX