Say I'm building targets A, B, and C in one project. In meson, is it possible to define dependency relationships between them?
For example, if the dependency graph looks like this:
A -> C
B -> C
How could I express this with meson?
Yes, it is possible to define intra-project dependencies. I found this test case on github.com to demonstrate how to do it. You can also refer to the section on dependencies in the manual.
Say I have a meson.build file defining two targets:
project('Demonstrate Dependencies', 'cpp')
subdir('src')
subdir('proj')
proj builds a library that src will depend on. Then proj/meson.build will look something like this:
incdirs = include_directories('include')
proj_lib = static_library('proj', 'proj.c', include_directories : incdirs)
proj_dep = declare_dependency(
include_directories : incdirs
, link_with : proj)
And src/meson.build would look something like:
exe = executable('proj_exe', 'main.c', dependencies : proj_dep)
Related
I would like to package lets say a binary with the pkg_tar command. But I would also automatically like it to include all deps to that binary, for example all .so files from other Bezel targets that are referenced with deps. Is it possible?
pkg_tar(
name = "example",
srcs = ["//myprogram"], # This only packages myprogram target
mode = "0644",
)
Currently, this feature isn't officially supported. You have three basic options:
explicitly enumrate all deps
use one of "hacks" from https://github.com/bazelbuild/bazel/issues/1920
use undocumented include_runfiles = True feature https://github.com/bazelbuild/rules_pkg/issues/145
Setting the (undocumented) include_runfiles = True will include the shared object and any other runfiles of all the transitive dependencies.
I am using Dune for building OCaml projects and I'd like to build a standalone library for reusing it in other projects.
The root folder of the library is mylib and the library was initialized with dune init lib mylib src (after cd mylib).
The directory tree of mylib, the root of the project, is the following:
mylib
+---dune-project
│
+---src
dune
priv.ml
mymodule.ml
mymodule.mli
Here follows the content of the files.
mylib/dune-project:
(lang dune 2.7)
mylib/src/dune:
(library
(name mylib))
mylib/src/priv.ml:
let rec loop a accu i =
let n = Array.length a in
if i = n then
accu
else
loop a (accu + Array.unsafe_get a i) (succ i)
mylib/src/mymodule.mli:
val sum : int array -> int
mylib/src/mymodule.ml:
let sum a =
Priv.loop a 0 0
After giving context and showing the content of each file of this toy example, the question follows:
How can I build the library mylib and use it in another, separate project?
(For example, in another project, I'd consume the library with the following:
Open Mylib
let () =
print_int (Mymodule.sum [1;2;3])
OR
let () =
print_int (Mylib.Mymodule.sum [1;2;3])
)
With Dune, given the executable main, you would write the following dune file to use library mylib if it was published on Opam.
dune:
(executable
(name main)
(libraries mylib))
After successfully building the library and linking it in another project, how can I hide or not expose some modules? For example, given the toy library of before, mylib, I would like to not expose and make inaccessible the module Priv (such that Priv would only be usable inside modules of mylib - like a protected/internal class in Java/C#).
I tried searching on Real World OCaml, Cornell CS3110 textbook, Dune documentation, OCaml Learn but, unless deeply nested, I found nothing.
Thank you very much for your help, if I didn't explain something in a clear way, please ask and I will try to explain better.
In the root directory, these should be a file called mylib.opam with content similar to this one. Then, the (public_name mylib) s-expression should be added to library in mylib/src/dune. Finally, making sure to be in the root of the project, the library shall be built with dune build and installed with opam install ..
For actually using the library in another project, even in a different dune workspace, all it's needed is to add (libraries mylib) to the dune file of project that will use the library.
The (private_modules priv) s-expression should be added to library in mylib/src/dune. Then, mylib.ml needs to be created with the following content: module Mymodule = Mymodule: this will make sure that only Mymodule will be exposed under the package Mylib.
I have two separate projects, A and B. Both have large folder structures, lots of dependencies and both have their own CMakelists.txt structures as well. Neither depend on each other.
I am adding new functionality to project A that depends on a header from project B, along with the network of files in Project B that header depends on.
I am at a loss for the correct way to link these with cmake. I added to header as an include where necessary in my code, but am not sure the correct way to link it. Do I use target_include_directories and add the binaries from project B, or the source code, or both? Project A won't be building B as it is already set up, with the binaries and source in separate subdirectories. I just need A to be able to call the functionality from B.
I am not very familiar with cmake yet, so any pointers would be appreciated.
Thanks.
Project B should export its targets.
That way, in project A, you could do something like this:
find_package(B REQUIRED)
target_link_libraries(A PUBLIC B::B)
And when invoking CMake, add B's build directory in the prefix path:
# in A/build
cmake .. -DCMAKE_PREFIX_PATH=/path/to/B/build
But in order for that to work, you must change your B CMake files to export your targets (as it should):
include(GNUInstallDirs)
add_library(B INTERFACE)
add_library(B::B ALIAS B)
target_link_libraries(B PUBLIC dependency-of-B)
target_compile_features(B INTERFACE cxx_std_17) # or any language version
# Set B include directory. Will add include directory for both B and A
target_include_directories(B PUBLIC
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/your-include-dir>
)
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/cmake/B-config.cmake" DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
install(TARGETS B EXPORT B-targets)
# install package
install(EXPORT B-targets
FILE B-targets.cmake
NAMESPACE B::
DESTINATION share/cmake/B
)
# export build tree
export(
EXPORT B-targets
FILE "${CMAKE_CURRENT_BINARY_DIR}/B-targets.cmake"
NAMESPACE B::
)
With B-config.cmake:
include(CMakeFindDependencyMacro)
# All find_package we used in CMakeLists.txt should also be there
find_dependency(dependency1 REQUIRED)
find_dependency(dependency2 REQUIRED)
include("${CMAKE_CURRENT_LIST_DIR}/B-targets.cmake")
If you have many target in B, you should install(TARGETS other-target EXPORT B-targets)
I strongly recommend looking at example of libraries that export their targets so you can base your work on it. For example, the glm library export its targets and always worked well. I also added target exportation in msdfgen project.
If you only want to use headers and not object files then just target_include_directories is all you need. Dependency tracking will be done by cmake and ninja/make automatically.
Alternatively, if you need to include both headers and objects from B, you'd really want to factor out these bits into small stand-alone static libraries within B, and then link with those libraries from A - this will add include file paths and everything else needed. cmake is quite good at it.
Scenario:
I'm porting an applications build system to CMake. Dependencies are already installed on the system or will be handled via conan.
Lets say the project is structured as following:
- include/
- BigFoo/
- *.hpp
- src/
- BigFoo/
- *.cpp
- main.cpp
- *.qml
- test/
- BigFoo/
- *Test.cpp
My goal is to reuse the compilation output (*.o) of BigFoo in the main application and the unit tests. I don't want an internal library (*.a or *.so) for BigFoo.
BigFoo is using Qt5 and Boost components from the target system. It also uses components provided as conan packages.
Current approach:
Build BigFoo as static library => handle dependencies via target_link_library()
Build main.cpp and *.qml => link with BigFoo
Build BigFoo/*Test.cpp => link with BigFoo
Desired approach:
Build BigFoo as object library => include dependency headers
Build main.cpp, *.qml with BigFoo_Object => link dependencies
Build BigFoo/*Test.cpp with BigFoo_Object => link dependencies
Problem of the desired approach:
I could not include dependency headers of several components (Boost::XYZ Qt5::XYZ CONAN_PKG::XYZ etc) via target_include_directories() when building an OBJECT library.
add_library(Core OBJECT)
# I want to do something like this:
target_include_directories(Core PUBLIC
Qt5::Core
Qt5::Qml
Qt5::Quick
Qt5::Scxml
CONAN_PKG::XYZ
CONAN_PKG::XYZ
)
The result is CMake (of course) adds header include paths like the following...
-I../../../Application/Qt5::Qml
And fails later because it cannot dismantle Qt include statements.
When building a static lib the header include was handled by target_link_libraries(), I'm now a bit confussed how to do this on a OBJECT library where I do not link anything.
My Questions:
How can I include headers of CMake targets provided by find_package() and CONAN_PKG in a OBJECT library target?
Is there is a better/nicer way of reusing BigFoo so i don't have duplicated compilation?
PS: I'm using cmake 3.13
I know that this seems nonsense, because object libraries aren't linked at all. But that is only one of the awkwardness of the CMake object libraries. This is what you probably need:
add_library(Core OBJECT)
target_link_libraries(Core PUBLIC
Qt5::Core
Qt5::Qml
Qt5::Quick
Qt5::Scxml
CONAN_PKG::XYZ
CONAN_PKG::XYZ
)
Object libraries may be used as the target (first) argument of target_link_libraries to specify dependencies of their sources on other libraries.
Here is my current project structure:
ProjectX
|_ projs
|_ A ( builds an external project POO version 1 )
add_executable(A ${A_HDRS} ${A_SRCS} $<TARGET_OBJECTS:libbar>)
|_ B ( builds an external project POO version 2 )
add_executable(B ${B_HDRS} ${B_SRCS} $<TARGET_OBJECTS:libbar>)
|
|_ libs
|_ libbar (objects only - no linking)
(needs POO either v1 or v2 depending on calling project)
issue lives here -->INCLUDE_DIRECTORIES(${POO_BUILD_DIR}/include)
add_library(bar OBJECT ${LIB_BAR_HDRS} ${LIB_BAR_SRCS})
GOAL:
I would like to be able to build from the top level including all projects and have libbar to be built with the correct dependencies. I would like to be able to have a continuous build process.
DETAILS:
When project A build builds, it needs to compile libbar with POO version1 and when project B builds it needs to compile libbar wtih POO version2. In either case it is still a version of POO. I would like to be able to pass the path to libbar from A or B.
ISSUE:
The POO_BUILD_DIR path is different depending on the project building libbar. When I build from the top level, make tries to build libbar first and doesn't find the correct includes.
QUESTION:
Does anyone know how to achieve this in cmake or how can I achieve finer grained control over the build order?
UPDATE and SOLUTION:
The problem that I was having could have been solved with Chris's solution below. However, my problem (that I should have realized earlier) is that even though it lives in a library directory and is called a library it's not a library. The naming and directory structure I can't change b/c I don't own the code base. However, I can change how I build it! My quote-unquote solution was to just include the files to the compilation like this: add_executable(A ... ${libbar_hdrs} ${libbar_srcs}
Moral of the Story
If someone tells you it's a library and names it a library - it still may not be. Or expressed in a colloquialism "Don't always believe what you're told".
Well there's lots of ways that you could do that, but one way that I have done it in a cmake C++ project is, for each library (each folder inside of /lib in my project root) I have a secondary Cmake script which builds that library, and I use add_subdirectory within my primary cmake script to invoke those secondary cmake scripts.
Here's an (open source) example from my project: https://github.com/cbeck88/cegui-emscripten
For instance, if you look here you'll see how I do "in tree" (what you are talking about) libs using add_subdirectory, vs. "out of tree" (user provided) libs which I find using find_package. https://github.com/cbeck88/cegui-emscripten/blob/17f0d097f989862035e977a6b9e0b1bbb1fcdf21/CMakeLists.txt#L58
if (FREETYPE_IN_TREE)
add_subdirectory(lib/freetype-2.5.5 freetype-2.5.5)
else()
LIST(APPEND CMAKE_PREFIX_PATH ${CMAKE_CURRENT_SOURCE_DIR}/lib/freetype-2.5.5-old )
find_package(freetype NO_CMAKE_FIND_ROOT_PATH)
MESSAGE ( STATUS "FREETYPE found = " ${FREETYPE_FOUND} )
endif()
This is what my secondary cmake script (in folder freetype-2.5.5) looks like, it will look very different in your case but at least it's an example. https://github.com/cbeck88/cegui-emscripten/blob/d24fcd6a5dc4697b8718564fadb25d76c255bce2/lib/freetype-2.5.5/CMakeLists.txt
Note especially some of these lines at the very end SET(FREETYPE_INCLUDE_DIRS ${INCL} PARENT_SCOPE) which you might need to use if you do it this way.