How to link against to specific packageid in Conan - conan

I have a package with 2 binaries. The binaries only differ by a single option.
The package is a library. How can now link this package to a specific package that I require?

There are few options:
You can use cmake_paths and discover the library name:
First, you add a conanfile.txt, declaring package name and cmake_paths generator
[requires]
my_package/0.1.0#user/channel
[generators]
cmake_paths
Second, you search the desired library from the package, by its name in your cmake file:
cmake_minimum_required(VERSION 3.0)
project(myapp)
find_library(MY_LIBRARY foo REQUIRED) # the library name foo in this example
add_executable(myapp app.cpp)
target_link_libraries (myapp ${MY_LIBRARY})
And finally, you pass the cmake_paths to cmake, so it will find your library
mkdir build && cd build
conan install ..
cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_paths.cmake
cmake --build .
./myapp
It works, but it's a bit fragile, as the consumer need to now the library name and there is no warning from CMake when the library is found, you have to add a condition to check it.
The second possible option is using Components feature, but requires a recipe modification, you can provide a different target for each library:
First, you need to update your conanfile.py, adding the components:
from conans import ConanFile, CMake
class MyPackage(ConanFile):
name = "my_package"
version = "0.1.0"
settings = "os", "compiler", "build_type", "arch"
options = {"shared": [True, False]}
default_options = {"shared": False}
generators = "cmake"
exports_sources = "src/*"
def build(self):
cmake = CMake(self)
cmake.configure(source_folder="src")
cmake.build()
def package(self):
self.copy("*.h", dst="include", src="src")
self.copy("*.lib", dst="lib", keep_path=False)
self.copy("*.dll", dst="bin", keep_path=False)
self.copy("*.dylib*", dst="lib", keep_path=False)
self.copy("*.so", dst="lib", keep_path=False)
self.copy("*.a", dst="lib", keep_path=False)
def package_info(self):
self.cpp_info.names["cmake_find_package"] = "MyPackage"
self.cpp_info.names["cmake_find_package_multi"] = "MyPackage"
self.cpp_info.components["libfoo"].names["cmake_find_package"] = "foo"
self.cpp_info.components["libfoo"].names["cmake_find_package_multi"] = "foo"
self.cpp_info.components["libfoo"].libs = ["foo"]
self.cpp_info.components["libbar"].names["cmake_find_package"] = "bar"
self.cpp_info.components["libbar"].names["cmake_find_package_multi"] = "bar"
self.cpp_info.components["libbar"].libs = ["bar"]
As you can see, the recipe builds a package with 2 libraries, foo and bar, and use different components for each one. As CamelCase is preferred for CMake targets, the name MyPackage will be used for the file name and target namespace. The result will be MyPackage::foo and MyPackage::bar.
As consumer, you have to update your project too:
Now we will use cmake_find_package generator, to avoid CMAKE_TOOLCHAIN_FILE in the command line:
[requires]
my_package/0.1.0#user/channel
[generators]
cmake_find_package
The CMake file now requires the package name, but it's checked by CMake:
cmake_minimum_required(VERSION 3.0)
project(myapp)
find_package(MyPackage REQUIRED)
add_executable(myapp app.cpp)
target_link_libraries (myapp MyPackage::foo) # We only need libfoo here
And finally, but simpler now, the command line:
mkdir build && cd build
conan install ..
cmake ..
cmake --build .
./myapp
Conan will generate FindMyPackage.cmake in build/ which will be loaded by your CMakeLists.txt.
Both demonstrations achieve what you asked, but I prefer the second, because is safer, as you can create a specific target, and avoid any mistake from the customer side.
NOTE: The feature Components requires Conan >=1.27.

Related

Debug symbols not stripped from resulting binaries in Yocto

Background
I am trying to build a custom software inside Yocto build. Software is built by CMake.
The following is my recipe - customsoftware.bb:
SRCBRANCH = "master"
SRCREV = "master"
MY_SRC = "OMITTED"
SRC_URI = "${MY_SRC};branch=${SRCBRANCH}"
# libraries dependencies
DEPENDS += "boost"
S = "${WORKDIR}/git"
B = "${WORKDIR}/build"
PARALLEL_MAKE ?= "-j 1"
inherit cmake
# My CMake Options
EXTRA_OECMAKE+=" -DSOME_OPTION=ON"
# I want unix makefiles instead on ninja build
OECMAKE_GENERATOR="Unix Makefiles"
The following is a watered down version of my cmake project - CMakeLists.txt
Please note: I have omitted irrelevant parts for brevity
cmake_minimum_required(VERSION 3.0.0)
#---------------------------------------------------------------------------------------
# set default build to release
#---------------------------------------------------------------------------------------
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose Release or Debug" FORCE)
endif()
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/dist/)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/dist/bin)
set(CMAKE_DISABLE_IN_SOURCE_BUILD ON)
set(CMAKE_DISABLE_SOURCE_CHANGES ON)
if ("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
message(FATAL_ERROR "
${BoldRed}Error:${ColourReset} In-source builds are not allowed. You should create separate directory for build files.
${Magenta}CMAKE_BINARY_DIR${ColourReset}(${CMAKE_SOURCE_DIR}) must be different from ${Magenta}CMAKE_SOURCE_DIR${ColourReset}(${CMAKE_BINARY_DIR})
")
endif ()
project(myapp)
find_package(Boost REQUIRED COMPONENTS thread)
add_executable(${PROJECT_NAME}
${HEADERS}
${SOURCES}
)
target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES})
#Copy entire contents of dist/ to /opt/myapp
install(DIRECTORY ${CMAKE_BINARY_DIR}/dist/
DESTINATION /opt/myapp
)
I have appended my recipe to image.
Issue
When I ran du -h tmp/work/.../<customsoftware>/build/dist/bin binary size is 80MB. Also, after deploying to target system binary size is 80MB.
UPDATE
As suggested in comments, binaries at tmp/work/.../<customsoftware>/image are not stripped. However, binaries at tmp/work/.../<customsoftware>/packages-split are stripped.
If I ran make in source of app - not through recipe and outside yocto - binary size is 1.7MB
Question
If I remember correctly, OE build will strip debug symbols from resulting binaries.
Why does my binary still get deployed with debug symbols? What have I missed?
How can I make sure only stripped - Release type - binary is deployed?
Explicitly specifying package types and inheriting pkgconfig solved my issue. Updated recipe:
SRCBRANCH = "master"
SRCREV = "master"
MY_SRC = "OMITTED"
SRC_URI = "${MY_SRC};branch=${SRCBRANCH}"
DEPENDS += "boost"
S = "${WORKDIR}/git"
PARALLEL_MAKE ?= "-j 1"
inherit pkgconfig cmake
EXTRA_OECMAKE+=" -DSOME_OPTION"
OECMAKE_GENERATOR="Unix Makefiles"
# Specify package types
PACKAGES = "${PN}-dbg ${PN}"
FILES_${PN}-dbg += "\
<INSTALL_PATH>/.debug \
"
FILES_${PN} += "\
<INSTALL_PATH>/* \
"
Can you please try to see if this simple Hello World is stripped or not in your environment?
recipe:
DESCRIPTION = "Simple helloworld cmake"
LICENSE = "MIT"
SECTION = "examples"
LIC_FILES_CHKSUM =
"file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
SRC_URI = "file://CMakeLists.txt \
file://helloworld.c"
S = "${WORKDIR}"
inherit cmake
EXTRA_OECMAKE = ""
CMakeLists.txt:
cmake_minimum_required(VERSION 2.8.10)
project(helloworld)
add_executable(helloworld helloworld.c)
install(TARGETS helloworld RUNTIME DESTINATION bin)
helloworld.c:
#include <stdio.h>
int main() {
printf("Hello World Makefile from CMake!\n");
return(0);
}
if you don't mind about debug version
you can do
OECMAKE_C_FLAGS_RELEASE += "-s"
OECMAKE_CXX_FLAGS_RELEASE += "-s"
It will strip your binaries

Using conan to package multiple configurations of preexisting binaries

I have a set of third-party binaries that I am trying to put into a conan package. The binaries are in folders for the build configuration: Linux32, Win32, Win64, Win32.
I have been able to produce a conan package for the Win64 configuration using the following conanfile.py:
from conans import ConanFile
class LibNameConan(ConanFile):
name = "LibName"
version = "1.1.1"
settings = "os", "compiler", "build_type", "arch"
description = "Package for LibName"
url = "None"
license = "None"
def package(self):
self.copy("*", dst="lib", src="lib")
self.copy("*.c", dst="include", src="include", keep_path=False)
def package_info(self):
self.cpp_info.libs = self.collect_libs()
I run the following commands in powershell:
conan install
mkdir pkg
cd pkg
conan package .. --build_folder=../
cd ..
conan export name/testing
conan package_files libname/1.1.1#name/testing
For the Win64 this works as expected. When I repeat the steps with Win32 binaries I do not get a different hash for the package.
I have tried running:
conan install -s arch=x86
However, this still results in the package having the same hash as the x86_64 configuration.
How is the configuration supposed to be set for generating a package from preexisting binaries?
If you are just packaging pre-built binaries, you are fine without the package() method, that is only relevant when building from the recipe:
from conans import ConanFile
class LibNameConan(ConanFile):
name = "LibName"
version = "1.1.1"
settings = "os", "compiler", "build_type", "arch"
description = "Package for LibName"
url = "None"
license = "None"
def package_info(self):
self.cpp_info.libs = self.collect_libs()
Unless there is some important reason you want to package the sources too, do you want them to be able to debug your dependencies too? In that case, please condition it to the build_type.
However this could be mostly irrelevant for your question. As your package doesn't have dependencies and you are not using any generator either, you don't need a conan install, and the settings you use there, have no effect.
You have to specify the settings for your binary configuration when you package_files:
$ conan package_files libname/1.1.1#name/testing # using your default config
$ conan package_files libname/1.1.1#name/testing -s arch=x86 # 32 bits instead of 64
...
Probably the recommended way is to use profiles:
$ conan package_files libname/1.1.1#name/testing # using your default profile
$ conan package_files libname/1.1.1#name/testing -pr=myprofile2
The documentation got recently a re-write, you might want to check: https://docs.conan.io/en/latest/creating_packages/existing_binaries.html

BUILD_BYPRODUCTS and dependency cycle for cmake + ninja + googletest + ExternalProject_Add

Attempting to use external project to build google test like so.
# Add googletest
ExternalProject_Add( googletest
GIT_REPOSITORY https://github.com/google/googletest.git
# We don't need to run update command. Takes time
# and the version we initially d/l will shoudl be fine
CMAKE_ARGS = "-Dgtest_disable_pthreads=1"
# Don't run update
UPDATE_COMMAND ""
# Disable install step
INSTALL_COMMAND ""
# BUILD_BYPRODUCTS googletest-prefix/src/googletest-stamp/googletest-gitinfo.txt
# BUILD_BYPRODUCTS googletest-prefix/tmp/googletest-cfgcmd.txt
BUILD_BYPRODUCTS "googletest-prefix/src/googletest-build/googlemock/libgmock_main.a"
)
# Get include dirs for googletest framework
ExternalProject_Get_Property(googletest source_dir)
set(GTEST_INCLUDE_DIRS
${source_dir}/googlemock/include
${source_dir}/googletest/include
)
# Create library target for gmock main, which is used to create
# test executables
ExternalProject_Get_Property(googletest binary_dir)
set(GTEST_LIBRARY_PATH ${binary_dir}/googlemock/libgmock_main.a)
set(GTEST_LIBRARY gmock_main)
add_library(${GTEST_LIBRARY} UNKNOWN IMPORTED)
set_property(TARGET ${GTEST_LIBRARY} PROPERTY IMPORTED_LOCATION ${GTEST_LIBRARY_PATH})
add_dependencies(${GTEST_LIBRARY} googletest)
With the ninja generator I get the below warning.
Policy CMP0058 is not set: Ninja requires custom command byproducts to be
explicit. Run "cmake --help-policy CMP0058" for policy details. Use the
cmake_policy command to set the policy and suppress this warning.
This project specifies custom command DEPENDS on files in the build tree
that are not specified as the OUTPUT or BYPRODUCTS of any
add_custom_command or add_custom_target:
googletest-prefix/src/googletest-stamp/googletest-gitinfo.txt
googletest-prefix/tmp/googletest-cfgcmd.txt
For compatibility with versions of CMake that did not have the BYPRODUCTS
option, CMake is generating phony rules for such files to convince 'ninja'
to build.
Project authors should add the missing BYPRODUCTS or OUTPUT options to the
custom commands that produce these files.
If I oblige the request of the cmake error by uncommenting the build byproducts lines in my external project command, I get a cyclical dependency error. However, if I leave the build byproducts out of it, the project seems to build just fine.
$ ninja
ninja: error: dependency cycle: googletest-prefix/src/googletest-stamp/googletest-configure -> googletest-prefix/tmp/googletest-cfgcmd.txt -> googletest-prefix/src/googletest-stamp/googletest-configure
I'm using cmake 3.4, ninja 1.6, and running on Windows using MSYS2 package.
I added cmake_policy(SET CMP0058 NEW) to my toplevel CMakeLists.txt file as the --help-policy text explains to. It no longer generates the warnings afterwards. I guess those files aren't needed. Not sure how they're getting picked up as dependencies.
Try to use something like in ExternalProject_Add function:
set(GMOCK_FILE_DIR "gmock-${GMOCK_VERSION}/src/googletest_github-build/googlemock/")
BUILD_BYPRODUCTS "${GMOCK_FILE_DIR}gtest/libgtest_main.a"
BUILD_BYPRODUCTS "${GMOCK_FILE_DIR}gtest/libgtest.a"
BUILD_BYPRODUCTS "${GMOCK_FILE_DIR}libgmock_main.a"
BUILD_BYPRODUCTS "${GMOCK_FILE_DIR}libgmock.a"

cmake external projects command seems to ignore INSTALL_DIR

First off, I'm relatively new to cmake. I'm trying to use cmake to build a project with a single external dependency. I specify the INSTALL_DIR for the external project to be CMAKE_INSTALL_PREFIX, so it installs to the same place as the parent project. But when I run make, it ignores it and tries to install to /usr/local/lib.
Here's my CMakeList.txt:
cmake_minimum_required( VERSION 2.8 )
include( ExternalProject )
project( capture )
add_library( capture SHARED capture.cc )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" )
ExternalProject_Add( proj_exceptions
GIT_REPOSITORY /home/user/workspace/exceptions
INSTALL_DIR ${CMAKE_INSTALL_PREFIX}
)
add_library( exceptions SHARED IMPORTED )
set_property( TARGET exceptions
PROPERTY IMPORTED_LOCATION ${CMAKE_INSTALL_PREFIX}/lib/libexceptions.so
)
add_dependencies( exceptions proj_exceptions )
include_directories( ${CMAKE_INSTALL_PREFIX}/include )
target_link_libraries( capture exceptions )
install( TARGETS capture DESTINATION lib )
install( FILES capture.h DESTINATION include )
CMakeLists.txt for the external project looks like this:
cmake_minimum_required( VERSION 2.8 )
project( exceptions )
add_library( exceptions SHARED exceptions.cc )
install( TARGETS exceptions DESTINATION lib )
install( FILES exceptions.hh DESTINATION include )
It clones and builds the external project just fine, but it chokes on the install step:
Install the project...
-- Install configuration: ""
-- Installing: /usr/local/lib/libexceptions.so
CMake Error at cmake_install.cmake:42 (file):
file INSTALL cannot copy file
"/home/user/workspace/capture/build/proj_exceptions-prefix/src/proj_exceptions-build/libexceptions.so"
to "/usr/local/lib/libexceptions.so".
Makefile:66: recipe for target 'install' failed
As you can see, the install configuration is empty. Looking through the generated config for the external project, I found this in cmake_install.cmake:
if(NOT DEFINED CMAKE_INSTALL_PREFIX)
set(CMAKE_INSTALL_PREFIX "/usr/local")
endif()
So, it seems that passing INSTALL_DIR to ExternalProject_Add doesn't set the install prefix. The install step succeeds, if I instead use:
ExternalProject_Add( proj_exceptions
GIT_REPOSITORY /home/djones/workspace/exceptions
CMAKE_ARGS "-DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}"
)
So what's the purpose of INSTALL_DIR then?
You're right for the purpose of INSTALL_DIR, but you may have missed some steps.
According the cmake 2.8 doc about external project:
Install Step
The INSTALL_DIR is underneath the calling project’s
binary directory. Use INSTALL_DIR to specify a different location.
Note that in addition to setting INSTALL_DIR, you also have to pass
-DCMAKE_INSTALL_PREFIX or --prefix to the CMake or configure command. It is not used automatically in the configure step since not all
projects follow this convention.
# [INSTALL_DIR dir]
You can refer to the install directory in your configure command, for
example:
CONFIGURE_COMMAND SOURCE_DIR/configure --prefix=INSTALL_DIR
# [INSTALL_COMMAND cmd...]
CMake-based projects use ‘cmake--build’ to build the install target.
Other projects use ‘make install’. Use INSTALL_COMMAND to customize
the install step. Use INSTALL_COMMAND “” to omit the install step. The
install command executes with the working directory set to
.
So try to update your cmake command, or use the custom INSTALL_COMMAND feature.

Cmake with bitbake recipe

I am trying to build an yocto image with my own package. I have OpenCV code on github which uses cmake.
I trying to write a recipe for it and facing lot of errors. Can any one give some hints on what functions or parameters to include in my recipe. My recipe looks as following
DESCRIPTION = "cameracapture application"
SECTION = "examples"
LICENSE = "CLOSED"
PR = "r0"
DEPENDS += "opencv"
SRC_URI = "git://https://github.com/zafrullahsyed/cameracapture.git;protocol=https;tag=v0.1"
EXTRA_OECMAKE=""
do_configure() {
cmake ../
}
inherit pkgconfig cmake
I followed these tutorials to write my recipe with cmake but in vain:
Bitbake Player recipe
Cmake-Bitbake-QT
The correct way of writing own recipes with cmake as follows:
DESCRIPTION = "cameracapture application"
SECTION = "examples"
LICENSE = "CLOSED"
PR = "r0"
DEPENDS = "opencv"
SRC_URI = "git://github.com/zafrullahsyed/cameracapture.git;protocol=https;tag=v0.1"
S = "${WORKDIR}/git"
inherit pkgconfig cmake
do_install() {
install -d ${D}${bindir}
install -m 0755 cameracapture ${D}${bindir}
}
Previously I didn't add do_install that's the reason yocto downloads the recipe but unable to include it Image.
If the CMakeLists.txt uses the install command then bitbake will do the install for you and you won't need to define you own do_install.
install(TARGETS cameracapture DESTINATION bin)
add the source directory in your recipe.
example
S = "${WORKDIR}/cameracapture
S is the source code path where your CMakeList.txt.
any how your are inheriting the cmake bbclass in your recipe, so it will take care of all configure , compile and install functionalities.
after doing this you can remove you do_configure function in the above recipe also.
you can add your make options if any to the below macro (as you kept empty).
example
EXTRA_OECMAKE = "all"