Conan 是 C 和 C++ 语言的依赖项和包管理器。它是免费和开源的,适用于所有平台(Windows、Linux、OSX、FreeBSD、Solaris 等),可用于开发所有目标,包括嵌入式、移动(iOS、Android)和裸机。它还与 CMake、Visual Studio (MSBuild)、Makefiles、SCons 等所有构建系统集成,包括专有系统。 它专为加速 C 和 C++ 项目的开发和持续集成而设计和优化。通过完整的二进制包管理,它可以为任意数量的不同版本的包创建和重用任意数量的不同二进制文件(用于不同的配置,如架构、编译器版本等),在所有平台上使用完全相同的过程。由于它是去中心化的,因此很容易运行自己的服务器来私下托管自己的包和二进制文件,而无需共享它们。@《Conan官方文档》
在上一篇博客《conan入门(四):conan 引用第三方库示例》中我们以cJSON为例说明了如何在项目中引用一个conan 包。那是比较简单的一种编译本机目标代码的应用场景(编译环境是Windows,目标代码也是Windows平台)。在物联应用的大背景下,C/C++开发中跨平台交叉编译的应用是非常广泛的。在使用conan来管理C/C++包(制品库)的环境下,如何实现对交叉编译的支持呢?因为我的工作涉及不少嵌入式平台的开发,conan对交叉编译的支持是我最关心的部分。
本文还是以cJSON 为例 ,说明如何在交叉编译环境下使用Conan引入依赖库。
总得来说,很简单,只需要有工具链文件,就可以完成。
示例的所有源码都保存在GIT仓库 conan_example,请接克隆代码到本地:
git clone https://gitee.com/l0km/conan_example.git
示例程序conan_example,以JSON格式输出使用的cJSON库的版本号。
本文中将介绍如何交叉编译arm平台的conan_exmample示例程序。
要实现交叉首先要定义好工具链,我有一个DS-5 ARM的交叉编译器(arm-linux-gnueabihf
)。已经写好了交叉编译工具链文件
conan_example/cmake/ds5-arm-linux-gnueabihf.toolchain.cmake
# This one is important
SET(CMAKE_SYSTEM_NAME Generic)
SET(CMAKE_SYSTEM_PROCESSOR arm)
set(_compiler_prefix "${_compiler_prefix}")
if(NOT EXISTS ${_compiler_prefix})
if(NOT $ENV{CROSS_COMPILER_PREFIX} STREQUAL "")
set(_compiler_prefix $ENV{CROSS_COMPILER_PREFIX})
elseif(CROSS_COMPILER_PREFIX)
set(_compiler_prefix ${CROSS_COMPILER_PREFIX})
else()
find_program(_armcc_path armcc)
if(NOT _armcc_path)
message(FATAL_ERROR "NOT FOUND compiler armcc in system path")
endif()
get_filename_component(_bin ${_armcc_path} DIRECTORY )
get_filename_component(_compiler_prefix ${_bin} DIRECTORY )
endif()
endif()
set(_suffix)
if(WIN32)
set(_suffix .exe)
endif()
#INCLUDE(CMakeForceCompiler)
# Specify the cross compiler
#SET(CMAKE_C_COMPILER "${_compiler_prefix}/bin/armcc${_suffix}")
#SET(CMAKE_CXX_COMPILER "${_compiler_prefix}/bin/armcc${_suffix}")
#SET(CMAKE_AR "${_compiler_prefix}/bin/armar${_suffix}" CACHE FILEPATH "Archiver")
SET(CMAKE_C_COMPILER "${_compiler_prefix}/../gcc/bin/arm-linux-gnueabihf-gcc${_suffix}")
SET(CMAKE_CXX_COMPILER "${_compiler_prefix}/../gcc/bin/arm-linux-gnueabihf-g++${_suffix}")
#CMAKE_C_COMPILER("${_compiler_prefix}/sw/gcc/bin/arm-linux-gnueabihf-gcc${_suffix}" GNU)
#CMAKE_CXX_COMPILER ("${_compiler_prefix}/sw/gcc/bin/arm-linux-gnueabihf-g++${_suffix}" GNU)
UNSET(CMAKE_C_FLAGS CACHE)
#SET(CMAKE_C_FLAGS "--cpu=Cortex-A9 --thumb -Ospace" CACHE STRING "" FORCE)
UNSET(CMAKE_CXX_FLAGS CACHE)
#SET(CMAKE_CXX_FLAGS ${CMAKE_C_FLAGS} CACHE STRING "" FORCE)
UNSET(CMAKE_EXE_LINKER_FLAGS CACHE)
#SET(CMAKE_EXE_LINKER_FLAGS "" CACHE STRING "" FORCE)
UNSET(CMAKE_AR_FLAGS CACHE)
#SET(CMAKE_AR_FLAGS "-p -armcc,-Ospace" CACHE STRING "" FORCE)
# set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> cr <TARGET> <LINK_FLAGS> <OBJECTS>")
#SET(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> ${CMAKE_AR_FLAGS} -o <TARGET> <OBJECTS>" CACHE STRING "C Archive Create")
# set(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> cr <TARGET> <LINK_FLAGS> <OBJECTS>")
#SET(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> ${CMAKE_AR_FLAGS} -o <TARGET> <OBJECTS>" CACHE STRING "CXX Archive Create")
#include_directories("${_compiler_prefix}/include")
include_directories("${_compiler_prefix}/../gcc/arm-linux-gnueabihf/libc/usr/include/arm-linux-gnueabi")
# Where is the target environment
SET(CMAKE_FIND_ROOT_PATH "${_compiler_prefix}/../gcc/arm-linux-gnueabihf/libc")
# Search for programs in the build host directories
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# For libraries and headers in the target directories
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
unset(_compiler_prefix)
先要安装arm平台的cjson库,显然,conan中央仓库没有预编译好的arm版本的cJSON库,我们需要通过定义环境变量CONAN_CMAKE_TOOLCHAIN_FILE
指定工具链文件,执行conan install
时conan找不到arm平台的库就会自动根据CONAN_CMAKE_TOOLCHAIN_FILE
定义的工具链接文件完成arm平台库的编译
$ export CONAN_CMAKE_TOOLCHAIN_FILE=/j/conan_example/cmake/ds5-arm-linux-gnueabihf.toolchain.cmake
关于CONAN_CMAKE_TOOLCHAIN_FILE
及其他conan环境变量定义更详细说明参见Conan官方文档《Environment variables》
如上篇博客差不多,执行conan install
安装arm平台的cJSON库
$ cd conan_example
$ mkdir build && cd build
$ conan install .. -s os=Linux -s arch=armv7 -s compiler=gcc -s compiler.version=4.8 --build cjson
Configuration:
[settings]
arch=armv7
arch_build=x86_64
build_type=Release
compiler=gcc
compiler.version=4.8
os=Linux
os_build=Windows
[options]
[build_requires]
[env]
cjson/1.7.13: Not found in local cache, looking in remotes...
cjson/1.7.13: Trying with 'conancenter'...
Downloading conanmanifest.txt completed [0.17k]
Downloading conanfile.py completed [6.55k]
Downloading conan_export.tgz completed [0.25k]
Decompressing conan_export.tgz completed [0.00k]
cjson/1.7.13: Downloaded recipe revision 0
cjson/1.7.13: Forced build from source
conanfile.txt: Installing package
Requirements
cjson/1.7.13 from 'conancenter' - Downloaded
Packages
cjson/1.7.13:5c3af8d1e83ce3e5b674d9e36b307da418be8145 - Build
Cross-build from 'Windows:x86_64' to 'Linux:armv7'
Installing (downloading, building) binaries...
Downloading conan_sources.tgz completed [0.25k]
Decompressing conan_sources.tgz completed [0.00k]
cjson/1.7.13: Configuring sources in C:\Users\guyadong\.conan\data\cjson\1.7.13\_\_\source
Downloading v1.7.13.tar.gz completed [346.14k]
cjson/1.7.13: Copying sources to build folder
cjson/1.7.13: Building your package in C:\Users\guyadong\.conan\data\cjson\1.7.13\_\_\build\5c3af8d1e83ce3e5b674d9e36b307da418be8145
cjson/1.7.13: Generator cmake created conanbuildinfo.cmake
cjson/1.7.13: Aggregating env generators
cjson/1.7.13: Calling build()
-- The C compiler identification is GNU 4.8.3
-- The CXX compiler identification is GNU 4.8.3
-- Check for working C compiler: E:/DS-5-v5.26.0/sw/ARMCompiler5.06u4/../gcc/bin/arm-linux-gnueabihf-gcc.exe
-- Check for working C compiler: E:/DS-5-v5.26.0/sw/ARMCompiler5.06u4/../gcc/bin/arm-linux-gnueabihf-gcc.exe - works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: E:/DS-5-v5.26.0/sw/ARMCompiler5.06u4/../gcc/bin/arm-linux-gnueabihf-g++.exe
-- Check for working CXX compiler: E:/DS-5-v5.26.0/sw/ARMCompiler5.06u4/../gcc/bin/arm-linux-gnueabihf-g++.exe - works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Conan: called by CMake conan helper
-- Conan: called inside local cache
-- Conan: Adjusting output directories
-- Conan: Using cmake global configuration
-- Conan: Adjusting default RPATHs Conan policies
-- Conan: Adjusting language standard
-- Conan: Adjusting fPIC flag (ON)
-- Conan: Checking correct version: 4.8
-- Performing Test FLAG_SUPPORTED_fvisibilityhidden
-- Performing Test FLAG_SUPPORTED_fvisibilityhidden - Success
-- Configuring done
-- Generating done
CMake Warning:
Manually-specified variables were not used by the project:
CMAKE_EXPORT_NO_PACKAGE_REGISTRY
-- Build files have been written to: C:/Users/guyadong/.conan/data/cjson/1.7.13/_/_/build/5c3af8d1e83ce3e5b674d9e36b307da418be8145/build_subfolder
Scanning dependencies of target cjson
[ 50%] Building C object source_subfolder/CMakeFiles/cjson.dir/cJSON.c.obj
[100%] Linking C static library ..\lib\libcjson.a
[100%] Built target cjson
cjson/1.7.13: Package '5c3af8d1e83ce3e5b674d9e36b307da418be8145' built
cjson/1.7.13: Build folder C:\Users\guyadong\.conan\data\cjson\1.7.13\_\_\build\5c3af8d1e83ce3e5b674d9e36b307da418be8145
cjson/1.7.13: Generated conaninfo.txt
cjson/1.7.13: Generated conanbuildinfo.txt
cjson/1.7.13: Generating the package
cjson/1.7.13: Package folder C:\Users\guyadong\.conan\data\cjson\1.7.13\_\_\package\5c3af8d1e83ce3e5b674d9e36b307da418be8145
cjson/1.7.13: Calling package()
[100%] Built target cjson
Install the project...
-- Install configuration: "Release"
-- Installing: C:/Users/guyadong/.conan/data/cjson/1.7.13/_/_/package/5c3af8d1e83ce3e5b674d9e36b307da418be8145/include/cjson/cJSON.h
-- Installing: C:/Users/guyadong/.conan/data/cjson/1.7.13/_/_/package/5c3af8d1e83ce3e5b674d9e36b307da418be8145/lib/pkgconfig/libcjson.pc
-- Installing: C:/Users/guyadong/.conan/data/cjson/1.7.13/_/_/package/5c3af8d1e83ce3e5b674d9e36b307da418be8145/lib/libcjson.a
-- Installing: C:/Users/guyadong/.conan/data/cjson/1.7.13/_/_/package/5c3af8d1e83ce3e5b674d9e36b307da418be8145/lib/cmake/cJSON/cJSONConfig.cmake
-- Installing: C:/Users/guyadong/.conan/data/cjson/1.7.13/_/_/package/5c3af8d1e83ce3e5b674d9e36b307da418be8145/lib/cmake/cJSON/cJSONConfigVersion.cmake
cjson/1.7.13 package(): Packaged 1 '.h' file: cJSON.h
cjson/1.7.13 package(): Packaged 1 '.a' file: libcjson.a
cjson/1.7.13 package(): Packaged 1 '.cmake' file: conan-official-cjson-targets.c
make
cjson/1.7.13 package(): Packaged 1 file: LICENSE
cjson/1.7.13: Package '5c3af8d1e83ce3e5b674d9e36b307da418be8145' created
cjson/1.7.13: Created package revision a991a9101873de809042280c2b48122c
conanfile.txt: Generator cmake created conanbuildinfo.cmake
conanfile.txt: Generator txt created conanbuildinfo.txt
conanfile.txt: Aggregating env generators
conanfile.txt: Generated conaninfo.txt
conanfile.txt: Generated graphinfo
-s os=Linux -s arch=armv7 -s compiler=gcc -s compiler.version=4.8 指定交叉编译的目标平台编译器及版本 –build cjson 指定编译cjson库 –build 的可选值(可多个组合): --build never 禁止编译依赖包,只下载预编译的二进制包,如果没找到预编译包则报错不可与其他可选值组合 --build missing 如果依赖包中没有找到预编译的二进制包则从源码编译 --build outdated 如果依赖包中没有找到预编译的二进制包或过期(日期旧于源码)则从源码编译 --build cascade --build pattern 编译包名匹配pattern的所有包 --build undefined 编译包名匹配pattern的之外所有包 本示例中
--build json
是pattern 用法,所以--build json
也是一样的效果--build=json
也是有效的写法
关于conan install
命令更详细的说明参见Conan官方文档《conan install》
生成Makeifile 工程文件
$ cd conan_example/build
$ cmake .. -G "Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=J:\conan_example\cmake\ds5-arm-linux-gnueabihf.toolchain.cmake
-- The C compiler identification is GNU 4.8.3
-- The CXX compiler identification is GNU 4.8.3
-- Check for working C compiler: E:/DS-5-v5.26.0/sw/ARMCompiler5.06u4/../gcc/bin
/arm-linux-gnueabihf-gcc.exe
-- Check for working C compiler: E:/DS-5-v5.26.0/sw/ARMCompiler5.06u4/../gcc/bin
/arm-linux-gnueabihf-gcc.exe - works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: E:/DS-5-v5.26.0/sw/ARMCompiler5.06u4/../gcc/b
in/arm-linux-gnueabihf-g++.exe
-- Check for working CXX compiler: E:/DS-5-v5.26.0/sw/ARMCompiler5.06u4/../gcc/b
in/arm-linux-gnueabihf-g++.exe - works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Conan: Adjusting output directories
-- Conan: Using cmake global configuration
-- Conan: Adjusting default RPATHs Conan policies
-- Conan: Adjusting language standard
-- Current conanbuildinfo.cmake directory: J:/conan_example/build
-- Conan: Checking correct version: 4.8
-- Configuring done
-- Generating done
-- Build files have been written to: J:/conan_example/build
编译conan_example
$ cmake --build .
Scanning dependencies of target json_test
[ 50%] Building C object CMakeFiles/json_test.dir/json_test.c.obj
[100%] Linking C executable bin/json_test
[100%] Built target json_test
对于第三方库我们不需要每次都编译,可以上传到私有制品库
conan upload cjson/1.7.13 -r ${repo} --all
# ${repo}为私有制品库的名字,下同
下次再执行conan install …时就可以指定不编译
$ conan install .. -s os=Linux -s arch=armv7 -s compiler=gcc -s compiler.version=4.8 --build never -r ${repo}
# --build never 强制不编译
# -r ${repo} 指定从私有制品库获取