I have a meson.build like this:
project('foobar', 'cpp',
version : '0.1',
default_options : ['warning_level=3',
'cpp_std=c++17',
'cmake_prefix_path=/foo/bar/')
cv2 = dependency('OpenCV', version : '>=4.0.0', default_options : [ 'cmake_prefix_path=/usr/local/' ])
exe = executable(foobar, foobar.cpp,
dependencies : [ cv2 ])
I set a global prefix to find cmake dependencies, but I need a way to override this path for single dependencies, as I have multiple versions installed in different locations.
How do I tell meson to look in a specific prefix?
Related
everyone.
I have a C++ project that uses MongoDB and wxWidgets as its dependencies, and the project is structured into multiple subdirectories.
I have recently started using the Meson build system but have no idea how to configure the meson.build file for this project structure.
Here is how my project is structured:
Project/
meson.build
BuildDir/
Source/
A/
meson.build
A1.hpp
A1.cpp
A2.hpp
A2.cpp
...
B/
meson.build
B1.hpp
B1.cpp
B2.hpp
B2.cpp
...
C/
meson.build
C1.hpp
C1.cpp
C2.hpp
C2.cpp
...
Thank you.
in your project A,B and C are sub project,
so a possible solution is on every sub project have a structure like that:
project(
'A',
'cpp',
version : '1.0.0',
default_options : ['warning_level=3']
)
project_description = ' ....'
sourceRoot = meson.source_root()
project_headers = [ # add your project headers ]
public_headers = [# add public header ]
build_args = [#add build args.... ]
# ======
# Target
# ======
#shared or static lib or executable....
project_target = shared_library( ...... )
# =======
# Project
# =======
# Make this library usable as a Meson subproject.
project_dep = declare_dependency(
include_directories: public_headers
)
set_variable(meson.project_name() + '_dep', project_dep)
# Make this library usable from the system's
# package manager.
#install_headers(project_headers, subdir : meson.project_name())
pkg_mod = import('pkgconfig')
pkg_mod.generate(
name : meson.project_name(),
filebase : meson.project_name(),
description : project_description,
subdirs : meson.project_name(),
)
an the same for B,C sub project,
than in the main meson must specify sub projects folders and add the dependency
...
project(
'MyProjj',
'cpp',
version : '1.1.0',
default_options : ['buildtype=plain','warning_level=3'],
subproject_dir : 'Source',
meson_version: '>= <the version you want to use>'
)
.......
dependency('A', fallback : ['<A path>', 'A_dep']),
dependency('B', fallback : ['<B path>', 'B_dep']),
dependency('C', fallback : ['<C path>', 'C_dep']),
so referring to your example:
Project/
meson.build
BuildDir/
Source/
A/
...
"A path" is A,
and the first parameter of dependency(...) is the names of the dependency too look up
I have a project A that uses meson as the build system and another project B that depends on A.
A runs, compiles and passes all tests. I installed A by doing meson install, which put all the headers and shared library objects where I needed them to be.
After installing A I want to compile B so I added:
A = dependency('A', include_type : 'system')
exe = executable(
'B',
src,
dependencies: [
A
],
cpp_args : '-DSHADER_PATH="' + meson.current_source_dir() + '/"',)
To the meson.build of B. meson does find A as a package and starts compiling B but fails to link. A defines a plethora of small utilities, each one as its own independent .so binary, all of which need to be linked against. Looking at the commands executed when compiling B, the directory where A's .so libraries are is added to the path using -L, but none of the libraries in that directory are listed for linking. So linking fials because the symbols in those binaries are not found (obviously they are not linked).
What do I need to specify in A to let it know a given library needs to be linked by default when the project is used as a dependency?
For example this is what one of the utilities of A looks like:
renderer_so_relative_path = \
'' + renderer_lib.full_path().replace(meson.build_root() + '/', '')
peripheral_so_relative_path = \
'' + peripheral_lib.full_path().replace(meson.build_root() + '/', '')
loader_sources = [
'ModuleStorage.cpp',
'CLI.cpp'
]
install_subdir('.', install_dir : 'include/ModuleStorage/')
loader_lib = library(
'ne_loader',
sources : loader_sources,
cpp_args : [
'-DNE_RENDERER_PATH="' + renderer_so_relative_path + '"',
'-DNE_PERIPHERAL_PATH="' + peripheral_so_relative_path + '"'
],
link_with : [],
include_directories : [],
dependencies : [core_dep, image_dep, argparse_dep, glfw],
install: true)
module_storage_dep = declare_dependency(link_with:loader_lib, include_directories: ['..'])
subdir('Imgui')
Maybe this helps:
Add to your A project:
# C compiler
ccompiler = meson.get_compiler('c')
# Where is the lib:
a_lib_dir = '/install/dir'
# Find the lib:
a_lib = ccompiler.find_library('a_lib_name', dirs: a_lib_dir)
# Create dependency
a_lib_dep = declare_dependency(
dependencies: a_lib,
include_directories: include_directories(inc_dir)
)
And link the dependency in B:
# Dependencies
b_deps = []
b_deps += dependency('alib', fallback:['alib', 'a_lib_dep'])
# Your B object
b_lib = static_library( 'blib', src,
dependencies: b_deps,
etc...)
# Your B object as someone's dependency (if needed):
b_as_dep = declare_dependency(
link_with: b_lib,
include_directories: inc_dirs,
dependencies: b_deps)
I consider this a fairly fundamental requirement for a build system, but somehow it is not that straightforward - I've found 2 pieces of information, but without any luck yet:
The so-called official doc: https://docs.bazel.build/versions/main/cpp-use-cases.html#adding-dependencies-on-precompiled-libraries, it is really not much information
The cc_import reference:https://docs.bazel.build/versions/main/be/c-cpp.html#cc_import, which claimed for "allows users to import precompiled C/C++ libraries"
But for both cases, I don't see a way to specify the path/to/precompiled/lib, then how suppose it should work? I tried to ln the library folder into the Bazel workspace, but also got no luck.
Would really appreciate if you could shed lights on how to use an external dependency in Bazel, or point me to a real, working example.
Take a look at https://github.com/justbuchanan/bazel_rules_qt to see how a precompiled Qt5 version can be used with Bazel. The problem with precompiled libs is that you need them for every OS, compiler(-settings), platform. If you only target a specific OS + host compiler and target platform then precompiled libs are fine.
Think also about bazelizing your third-party library. I did this for instance for OpenEXR and oneTBB. I also hacked together some scripting to convert Visual Studio Project files to Bazel BUILD files.
Here is an example of how to use a precompiled OpenCV version on Windows:
WORKSPACE.bazel:
workspace(name = "OpenCVDemo")
load("#bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
# OpenCV
http_archive(
name = "opencv",
build_file = "//third_party:opencv.BUILD",
strip_prefix = "opencv/build",
# Release
url = "https://github.com/opencv/opencv/releases/download/4.3.0/opencv-4.3.0-dldt-2020.2-vc16-avx2.zip",
)
opencv.BUILD:
package(default_visibility = ["//visibility:public"])
MAIN_MODULES = [
"core",
"imgproc",
"imgcodecs",
"videoio",
"highgui",
"video",
"calib3d",
"features2d",
"objdetect",
"dnn",
"ml",
"flann",
"photo",
"stitching",
"gapi",
]
# https://stackoverflow.com/questions/56108940/how-to-specify-the-compiler-flags-to-be-used-in-opt-compilation-mode-by-my-own
config_setting(
name = "fastbuild_mode",
values = {"compilation_mode": "fastbuild"},
)
config_setting(
name = "dbg_mode",
values = {"compilation_mode": "dbg"},
)
cc_import(
name = "tbb",
shared_library = select({
":fastbuild_mode": "bin/tbb.dll",
":dbg_mode": "bin/tbb_debug.dll",
"//conditions:default": "bin/tbb.dll",
}),
)
[
(
cc_import(
name = module,
interface_library = select({
":fastbuild_mode": "lib/opencv_{}430.lib".format(module),
":dbg_mode": "lib/opencv_{}430d.lib".format(module),
"//conditions:default": "lib/opencv_{}430.lib".format(module),
}),
shared_library = select({
":fastbuild_mode": "bin/opencv_{}430.dll".format(module),
":dbg_mode": "bin/opencv_{}430d.dll".format(module),
"//conditions:default": "bin/opencv_{}430.dll".format(module),
}),
)
)
for module in MAIN_MODULES
]
cc_library(
name = "opencv",
hdrs = [
"include/opencv2/calib3d.hpp",
"include/opencv2/calib3d/calib3d.hpp",
"include/opencv2/calib3d/calib3d_c.h",
"include/opencv2/core.hpp",
"include/opencv2/core/hal/interface.h",
"include/opencv2/cvconfig.h",
"include/opencv2/dnn.hpp",
"include/opencv2/features2d.hpp",
"include/opencv2/flann.hpp",
"include/opencv2/flann/config.h",
"include/opencv2/flann/defines.h",
"include/opencv2/flann/miniflann.hpp",
"include/opencv2/highgui.hpp",
"include/opencv2/highgui/highgui.hpp",
"include/opencv2/highgui/highgui_c.h",
"include/opencv2/imgcodecs.hpp",
"include/opencv2/imgproc.hpp",
"include/opencv2/ml.hpp",
"include/opencv2/ml/ml.inl.hpp",
"include/opencv2/objdetect.hpp",
"include/opencv2/opencv.hpp",
"include/opencv2/opencv_modules.hpp",
"include/opencv2/photo.hpp",
"include/opencv2/stitching.hpp",
"include/opencv2/video.hpp",
"include/opencv2/video/background_segm.hpp",
"include/opencv2/video/tracking.hpp",
"include/opencv2/videoio.hpp",
"include/opencv2/videoio/videoio_c.h",
],
includes = ["include"],
deps = MAIN_MODULES + [
"tbb",
],
)
BUILD.bazel:
cc_binary(
name = "OpenCVDemo",
srcs = ["main.cpp"],
deps = ["#opencv"],
)
Should work similar for other libraries
I am want to package a CMake project with conan.
For that I use the following conanfile.py:
import os
from conans import ConanFile, tools
from conan.tools.cmake import CMake, CMakeToolchain
from conans.tools import Version
class BaseLibrary(ConanFile):
name = "base-library"
version = "1.0.0"
description = """This is a test project with a library base::io
and base::math and an executable cli."""
license = "MIT"
generators = "cmake_find_package_multi", "cmake_find_package",
default_options = {"fmt:shared": True}
build_policy = "missing" # if this package is build by default if missing.
settings = "os", "compiler", "build_type", "arch"
exports_sources = "*"
_cmake = None
def requirements(self):
if Version(self.version) >= "1.0.0":
self.requires("fmt/8.0.1")
def _configure_cmake(self):
if self._cmake:
return self._cmake
self._cmake = CMake(self)
self._cmake.configure(source_folder=".")
return self._cmake
def build(self):
cmake = self._configure_cmake()
cmake.build()
cmake.install()
def package(self):
cmake = self._configure_cmake()
cmake.install()
tools.rmdir(os.path.join(self.package_folder, "lib", "cmake"))
tools.rmdir(os.path.join(self.package_folder, "lib", "pkgconfig"))
tools.rmdir(os.path.join(self.package_folder, "share"))
def package_info(self):
self.cpp_info.names["cmake_find_package"] = "base"
self.cpp_info.names["cmake_find_package_multi"] = "base"
self.cpp_info.names["pkg_config"] = "base"
which is next to my main CMakeLists.txt file. The CMake project builds without problems and also has a proper install target which installs everything properly: bin,lib,include,share. In CMake I use the conan-cmake module with basically something like this.
When I run
conan create -s build_type=Release . demo/testing
I get the following weird error:
...
Requirements
base-library/1.0.0#demo/testing from local cache - Cache
fmt/8.0.1 from 'conancenter' - Cache
Packages
base-library/1.0.0#demo/testing:4f2b14d304ab8e4391d162a6eb44110cc27a3faa - Build
fmt/8.0.1:d4e9c4f02b4f03edf5a640dcd22779727d782e79 - Cache
Installing (downloading, building) binaries...
fmt/8.0.1: Already installed!
base-library/1.0.0#demo/testing: WARN: Build folder is dirty, removing it: /home/developer/.conan/data/base-library/1.0.0/demo/testing/build/4f2b14d304ab8e4391d162a6eb44110cc27a3faa
base-library/1.0.0#demo/testing: Configuring sources in /home/developer/.conan/data/base-library/1.0.0/demo/testing/source
base-library/1.0.0#demo/testing: Copying sources to build folder
base-library/1.0.0#demo/testing: Building your package in /home/developer/.conan/data/base-library/1.0.0/demo/testing/build/4f2b14d304ab8e4391d162a6eb44110cc27a3faa
base-library/1.0.0#demo/testing: Generator cmake_find_package created Findfmt.cmake
base-library/1.0.0#demo/testing: Generator cmake_find_package_multi created fmt-config-version.cmake
base-library/1.0.0#demo/testing: Generator cmake_find_package_multi created fmt-config.cmake
base-library/1.0.0#demo/testing: Generator cmake_find_package_multi created fmtTargets.cmake
base-library/1.0.0#demo/testing: Generator cmake_find_package_multi created fmtTarget-release.cmake
base-library/1.0.0#demo/testing: Aggregating env generators
base-library/1.0.0#demo/testing: Calling build()
base-library/1.0.0#demo/testing:
base-library/1.0.0#demo/testing: ERROR: Package '4f2b14d304ab8e4391d162a6eb44110cc27a3faa' build failed
base-library/1.0.0#demo/testing: WARN: Build folder /home/developer/.conan/data/base-library/1.0.0/demo/testing/build/4f2b14d304ab8e4391d162a6eb44110cc27a3faa
ERROR: base-library/1.0.0#demo/testing: Error in build() method, line 74
cmake = self._configure_cmake()
while calling '_configure_cmake', line 65
self._cmake = CMake(self)
ConanException: The file /home/developer/.conan/data/base-library/1.0.0/demo/testing/build/4f2b14d304ab8e4391d162a6eb44110cc27a3faa/conanbuild.conf does not exist. Please, make sure that it was not generated in another folder.
What is the problem here and how can I resolve this? I could not find anything related to this?
from conans import ConanFile, CMake
...
def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()
...
I had the same problem and finally found the issue:
The CMake you are importing is the one working with the CMakeToolchain which are both part of the conan.tools.cmake module.
The one that is described in the usage of cmake_find_package[ref] is the one in conans module
So replacing:
from conans import ConanFile, tools
from conan.tools.cmake import CMake, CMakeToolchain
by
from conans import ConanFile, tools, CMake
from conan.tools.cmake import CMakeToolchain
should fix your problem
I am trying to use yggdrasil-decision-forests (ydf) as an external dependence of a C++ project. According with ydf's own documentation, one should include the following in the WORKSPACE file:
http_archive(
name = "ydf",
strip_prefix = "yggdrasil_decision_forests-master",
urls = ["https://github.com/google/yggdrasil_decision_forests/archive/master.zip"],
)
load("#ydf//yggdrasil_decision_forests:library.bzl", ydf_load_deps = "load_dependencies")
ydf_load_deps(repo_name = "#ydf")
And the following on the BUILD file:
cc_binary(
name = "main",
srcs = ["main.cc"],
deps = [
"#ydf//yggdrasil_decision_forests/model/learner:learner_library",
"#com_google_absl//absl/status",
],
)
However, this seems no to work and returns the following error:
ERROR: some_path/WORKSPACE:9:1: name 'http_archive' is not defined
ERROR: error loading package '': Encountered error while reading extension file 'yggdrasil_decision_forests/library.bzl': no such package '#ydf//yggdrasil_decision_forests': error loading package 'external': Could not load //external package
Since the http_archiveseems to be the problem, I managed to get further along by using git_repository instead in the WORKSPACE file, like so:
git_repository(
name = "ydf",
remote = "https://github.com/google/yggdrasil-decision-forests.git",
branch = "0.1.3",
)
load("#ydf//yggdrasil_decision_forests:library.bzl", ydf_load_deps = "load_dependencies")
ydf_load_deps(repo_name = "#ydf")
And slightly changing the BUILD file like so, since the functions I intend to use are under the model:all_models target:
cc_library(
name = "models",
srcs = ["models.cpp"],
hdrs = ["models.h"],
deps = [
"#ydf//yggdrasil_decision_forests/model:all_models",
]
)
However, when I run bazel build :models with this configuration, I get the following error:
ERROR: some_path/BUILD:1:11: error loading package '#ydf//yggdrasil_decision_forests/model': in .cache/external/ydf/yggdrasil_decision_forests/utils/compile.bzl: in /some_path/.cache/external/com_google_protobuf/protobuf.bzl: Unable to find package for #rules_python//python:defs.bzl: The repository '#rules_python' could not be resolved. and referenced by '//:models'
Thus, from what I gathered, it seems that when I run build on my project, Bezel is not recursively pulling the dependencies of the package I am trying to use. This seems even more so the case, since if I clone the ydf and build the model:all_models target, all goes well. How can I force bazel to recursively pull the dependencies of the external dependencies that I am trying to use?