Objective
I am trying to have CMake find Doxygen on a bunch of different systems and configurations:
Online documentation is generated on Ubuntu
Local tests and development is done on Macos
Doxygen can be installed system-wide, through brew or through conan depending on the use case
Problem
I struggle finding a uniform approach that does not involve a lot of OS-specific operations. I am vaguely tempted to glue together the 3 following approaches, but I am still surprised/concerned/unsure a more elegant solution does not exist.
Sub-solution 1
What I have presently works only for system-wide installations:
find_package(Doxygen
REQUIRED dot
OPTIONAL_COMPONENTS mscgen dia)
if(DOXYGEN_FOUND)
# doxygen settings can be set here, prefixed with "DOXYGEN_"
# ...
# this target will only be built if specifically asked to.
# run "make docs" to create the doxygen documentation
doxygen_add_docs(
docs
${PROJECT_SOURCE_DIR}
COMMENT "Generate API-documents."
)
else (DOXYGEN_FOUND)
message([WARNING] " Doxygen need to be installed to generate the doxygen documentation")
endif (DOXYGEN_FOUND)
Sub-solution 2:
I am aware I can try to access Conan-installed executable through CONAN_BIN_DIRS_DOXYGEN/doxygen, as explained here
Sub-solution 3:
I am also aware I can try to locate Homebrew installations as described here.
Following #drodri comments, the following conan/conanfile.py achieves the desired result for my header-only library:
from conans import ConanFile, CMake
from conan.tools.cmake import CMakeDeps
class MyConan(ConanFile):
name = "mylib"
version = "0.1"
settings = "os", "compiler", "arch", "build_type"
exports_sources = "include/*", "CMakeLists.txt", "test/*", "cmake/*", "docs/*"
no_copy_source = True
generators = "cmake", "CMakeToolchain", "CMakeDeps"
requires = "boost/[>=1.78.0]", "gdal/[>=3.4.3]"
tool_requires = "cmake/3.24.2", "doxygen/1.9.4"
def generate(self):
cmake = CMakeDeps(self)
# generate the config files for the tool require
cmake.build_context_activated = ["doxygen/1.9.4"]
cmake.generate()
def build(self): # this is not building a library, just tests
cmake = CMake(self)
cmake.configure()
cmake.build()
cmake.test(output_on_failure=True)
def package(self):
self.copy("*.h")
def package_id(self):
self.info.clear()
It can be called with conan install conan/conanfile.py --build=missing --install-folder=build -pr:b=conan/profiles/clang_13 -pr:h=conan/profiles/clang_13
Related
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
I have a group of class files which are shared by several of our projects. We would like to start refactoring these classes, so I am starting by building a Conan package to allow us to version them. The sticky part is that they do not build on their own; there is coupling both ways between the shared classes and the consuming classes.
As such, I've been trying to build a Conan package which simply includes the .h & .cpp files but does not attempt to build them. My conanfile.py looks like this:
from conans import ConanFile, CMake
import os
class SharedcodeConan(ConanFile):
name = "SharedCode"
version = "1.0"
author = "me myemail"
description = ""
generators = "cmake", "visual_studio"
exports_sources = "*"
def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()
def package(self):
self.copy("*.h", dst="include")
self.copy("*.cpp", dst="src")
self.copy("*.rc", dst="src")
def package_info(self):
self.cpp_info.includedirs = ['include']
This all works well. I can create the package (specifying --test-folder=None). When I pull it down from Artifactory, the include & src folders contain the files I expect.
What I cannot figure is how to bring the .cpp files into my Visual Studio project. The Conan VS extension conveniently adds Visual Studio macros for the includes, linker, etc., but not for the source files. As such, my project finds the header files, but linking fails. In looking through the docs & the Conan source, I haven't seen an indication that this is currently possible.
Is there a way to dynamically reference the src folder?
Update: In light of the comments below stating this isn't supported currently, any workaround ideas are also welcome.
I need to figure out how to manage a recipe for a package based on CMake creating a very simple shared library.
The goal is to provide the .so library into the Yocto build system in an atomic way, so can be used by other recipes managing application level.
This is the simple cpp code
#include <iostream>
#include "Student.h"
using namespace std;
Student::Student(string name):name(name){}
void Student::display(){
cout << "A student with name " << this->name << endl;
}
This is kind of CMakeList.txt
cmake_minimum_required(VERSION 2.8.9)
project(directory_test)
set(CMAKE_BUILD_TYPE Release)
#Bring the headers, such as Student.h into the project
include_directories(include)
#However, the file(GLOB...) allows for wildcard additions:
file(GLOB SOURCES "*.cpp")
#Generate the shared library from the sources
add_library(testStudent SHARED ${SOURCES})
#Set the location for library installation
install(TARGETS testStudent DESTINATION lib)
install(FILES student.h DESTINATION include)
This is the recipe studentlib_0.1.bb
SUMMARY = "Cmake application - creates a library"
SECTION = "examples"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
SRC_URI = "\
file://CMakeLists.txt \
file://student.cpp \
file://student.h \
"
S = "${WORKDIR}"
inherit cmake
EXTRA_OECMAKE = ""
The problem is when I build the specific recipe studentlib
$ bitbake studentlib
...
Build Configuration:
BB_VERSION = "1.38.0"
BUILD_SYS = "x86_64-linux"
NATIVELSBSTRING = "universal"
TARGET_SYS = "arm-poky-linux-gnueabi"
MACHINE = "qemuarm"
DISTRO = "poky"
DISTRO_VERSION = "2.5.2"
TUNE_FEATURES = "arm armv5 thumb dsp"
TARGET_FPU = "soft"
...
NOTE: Executing RunQueue Tasks
ERROR: studentlib-0.1-r0 do_package_qa: QA Issue: -dev package contains non-symlink .so: studentlib-dev path '/work/armv5e-poky-linux-gnueabi/studentlib/0.1-r0/packages-split/studentlib-dev/usr/lib/libtestStudent.so' [dev-elf]
ERROR: studentlib-0.1-r0 do_package_qa: QA run found fatal errors. Please consider fixing them.
ERROR: studentlib-0.1-r0 do_package_qa: Function failed: do_package_qa
ERROR: Logfile of failure stored in: /home/me/yocto-qemuarm-sumo/poky/build/tmp/work/armv5e-poky-linux-gnueabi/studentlib/0.1-r0/temp/log.do_package_qa.21681
ERROR: Task (/home/me/yocto-qemuarm-sumo/poky/meta-me/recipes-cmake/studentlib/studentlib_0.1.bb:do_package_qa) failed with exit code '1'
How can I solve this Issue?
I can't find any example for explanation.
Thanks
In Yocto, files (which are installed in ${D} either manually in do_install or by the make, cmake, autotools, etc... in e.g. do_compile) are put in a package when they match one of the regular expression (or glob, not entirely sure about that) contained in FILES_foo.
One recipe can (and usually does) provide multiple packages. So you'd have multiple FILES_foo1 with their own paths to match.
In Yocto, the file is put in the first package where one of the paths in its FILE_foo matches the file. Even if the file matches the paths of other packages, it'll ever be in only one package, the first one.
FWIW, packages are created from leftmost to rightmost in PACKAGES variable in the recipe. By default, the PACKAGES variable is ${PN}-src ${PN}-dbg ${PN}-staticdev ${PN}-dev ${PN}-doc ${PN}-locale ${PACKAGE_BEFORE_PN} ${PN} (c.f. http://git.yoctoproject.org/cgit.cgi/poky/tree/meta/conf/bitbake.conf#n292).
The default FILES_* variables are defined in bitbake.conf as well, c.f. http://git.yoctoproject.org/cgit.cgi/poky/tree/meta/conf/bitbake.conf. Look for everything starting with FILES_.
In there, you can see that by default, FILES_${PN} has ${libdir}/lib*${SOLIBS} (c.f. http://git.yoctoproject.org/cgit.cgi/poky/tree/meta/conf/bitbake.conf#n296) packaged. SOLIBS is, by default, .so.* (c.f. http://git.yoctoproject.org/cgit.cgi/poky/tree/meta/conf/bitbake.conf#n280), which means only dot versions of libraries are packaged in the ${PN} package (if they are not matched by another package before). FILES_${PN}-dev on the other hand packages ${FILES_SOLIBSDEV} which defaults to ${base_libdir}/lib*${SOLIBSDEV} ${libdir}/lib*${SOLIBSDEV}, with SOLIBSDEV in turns defaults to .so (c.f. http://git.yoctoproject.org/cgit.cgi/poky/tree/meta/conf/bitbake.conf#n313, http://git.yoctoproject.org/cgit.cgi/poky/tree/meta/conf/bitbake.conf#n314 and http://git.yoctoproject.org/cgit.cgi/poky/tree/meta/conf/bitbake.conf#n283). Please note that library filenames should all start with lib to be able to be matched by the default FILES_*.
TL;DR: By default, lib*.so.* in FILES_${PN} and lib*.so in FILES_${PN}-dev.
That's the background needed to understand what is expected in which package. The issue is that -dev package should only contain lib*.so symlinks to versioned libraries (i.e. lib*.so.*).
People usually expect versioned libraries so it's easy to know which version is installed and against which version a particular software should be linked against. If the version does not matter or if the major version only matters, those will then link to the unversioned or major versioned symlinks to the versioned library.
Best practice dictates that behavior.
Two possible cases, either you only provide the unversioned library in which case the solution is to version your library in your cmake or in your recipe. Then everything works out of the box.
Or you have a copy of your versioned library named as an unversioned library, in which case you should delete your copy and just make a symlink to the versioned library.
If that is not an option (but please really consider it), you can try to find a way so that ${PN}-dev does not have this library.
There are multiple options: add lib*.so to FILES_${PN} and either remove the ${PN}-dev from the PACKAGES, remove lib*.so from FILES_${PN}-dev, unset FILES_${PN}-dev, ...
I just started to explore both conan and cmake for building and packaging C++ files. Here is a sample conanfile.py
from conans import ConanFile, CMake
class PocoTimerConan(ConanFile):
settings = "os", "compiler", "build_type", "arch"
requires = "Poco/1.7.8p3#pocoproject/stable"
generators = "cmake", "gcc", "txt"
default_options = {"Poco:shared": True, "OpenSSL:shared": True}
def imports(self):
self.copy("*.dll", dst="bin", src="bin") # From bin to bin
self.copy("*.dylib*", dst="bin", src="lib") # From lib to bin
def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()
Is there any option to build the same without the use of cmake. Thanks in advance.
Yes, Conan is Cross platform, build system agnostic
There is a list with all integrations available, which includes MS Build, QMake and Autotools.
If you don't want to use integration tools, you can run directly the build commands, including running the compiler commands:
def build(self):
self.run("gcc ...")
No, Conan uses whatever build system the library is using, wrapping it. In this case, Poco is using the CMake build system, so CMake is necessary to build it. It is not possible to replace a given build system by another one automatically, that level of automation does not exist.
That doesn't mean that Conan needs CMake to operate. Conan can work with any build system, including proprietary ones. For example:
Creating and using packages with Visual Studio
Create and reuse packages with Makefiles
How to create integrations for new and custom build systems
Also, take into account that the build system used to create the package can be different to the one to consume that package. Conan "generators" can generate files for the consuming build system on the fly.
Maybe you are interested in the concept of "build-requires". You can use Conan to automatically install the cmake version that you want as a Conan package, and use it, injecting it automatically to packages to be build. Check the documentation of "build-requires" here
I'm trying to have my recipe be compiled and linked against the arm libraries. I'm using cmake. I can't seem to figure out the right work flow, after having read trough multiple documents on the yocto site and reference materials. My approach right now is:
Set the source
Build my target minal image, without the layer that I want to use
Try to build my specific recipe: bitbake Test
I have downloaded the arm toolchain from the Yocto site, and prepared it in my sources/poky. Here I can see the systroots and all the libraries that I would need. My recipe bb file is the following:
# This file was derived from the 'Hello World!' example recipe in the
# Yocto Project Development Manual.
#
SUMMARY = "Project"
SECTION = "examples"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
SRC_URI = "file://."
S = "${WORKDIR}/project/src"
inherit pkgconfig cmake externalsrc
And my CMake file contains, among more:
link_directories(/media/traffic/Yocto/QorIQ-SDK-V2.0-20160527-yocto/sources/poky/sysroots/aarch64-poky-linux/usr/lib)
I'm able to compile a hello world project fine, but as soon as external libraries take a role, it goes wrong.
cannot find /usr/lib/libpthread_nonshared.a
/media/traffic/Yocto/QorIQ-SDK-V2.0-20160527-yocto/build_ls2084abluebox/tmp/sysroots/x86_64-linux/usr/bin/aarch64-fsl-linux/../../libexec/aarch64-fsl-linux/gcc/aarch64-fsl-linux/4.9.3/ld: cannot find /usr/lib/libpthread_nonshared.a
It seems to look in the wrong folder. Are the steps that I'm taking correctly? Or am i missing something?
Elmar
Which poky version are you using? I got exactly the same issue recently with another package. There are 2 issues here:
It cannot find the pThread library. I added a FindThreads.cmake in the tree and imported it. But then the linker could not make it. I went to the conclusion, cmake itself had an issue with this library and ended changing the poky commit to have a different version of CMake. Note that you can also keep the new poky versions and have the custom CMake in your layer.
CMake 3.7 and 3.8.2 were not working properly but the 3.7.1 was for me (hash c9a512b6408d4cc11c1b36f7bc1b9b1c31056ce1). To find out which commit, you can execute
git log --pretty=oneline | grep cmake: