Conan-center中保存了许多的c++包,但是还是有许多的c++源没有被打包,这次一边学习一边尝试为Clang进行打包

为第三方库进行打包

  1. 构建一个新pkg
conan new Clang/12.0.0 -t 
  1. 修改conanfile.py

直接去https://github.com/conan-io/conan-center-index/blob/master/recipes/下面参考各种打包的流程即可

  1. 下载代码到本地调试构建

注意每次build的时候最好把build目录的CmakeCache.txt删除了再开始,不然有时候你以为你成功,但其实只是偶尔的cache是正确的。

conan export . Clang/12.0.0@demo/testing # 修改代码后需要export才能生效 
conan install . --install-folder build_x86_64 -s arch=x86_64 # 如果我们的当前开发的代码需要依赖别的conan包,可以先把别的包install到对应目录 -s可以修改配置,默认配置在conan config下面
conan source . --install-folder build_x86_64 --source-folder src # 调用source方法下载源码并做修改
# 可以分别调用build的三个阶段使用conan对源码进行编译
conan build . --build-folder build_x86_64 --source-folder src --configure
conan build . --build-folder build_x86_64 --source-folder src --build
conan build . --build-folder build_x86_64 --source-folder src --install
# conan build . --build-folder build_x86_64 --source-folder src # 也可以一步到位
conan package . --build-folder build_x86_64 --package-folder=package_x86 # 打包
# 打包之后还需要同步到local cache中才能被其他包使用,调用这个命令可以自动打包
conan export-pkg . Clang/12.0.0@demo/testing --build-folder=build_x86_64 -s arch=x86
  1. 打包上传云端

如果上面的步骤之后,本地去include对应的代码可以正常编译,那么就可以导出pkg了

conan create .

注意点

  1. 如果需要修改第三方库的源码,可以用patch的形式,调用conan的方法进行修改。

通常都是要在第三方库中添加如下信息的,因为你所有的依赖都是交给conan了,而不是有的通过本机,有的通过Conan。conan会给所有的第三方库都生成一个findxxx.cmake,通过conan_basic_setup去执行,执行完毕后,find_package就可以找到来自与Conan的包了。同时这里的${CONAN_BIN_DIRS}也可以添加,添加之后可以调用预编译lib中的一些可执行文件。

还有就是有的库写的find_package都是用xxx_DIR的方式去寻找xxxConfig.cmake的,这种方式和conan的行为不一致,需要修改。

message(STATUS "Loading conan scripts for Clang dependencies...")
include("${CMAKE_BINARY_DIR}/conanbuildinfo.cmake")
message(STATUS "Doing conan basic setup")
conan_basic_setup()
list(APPEND CMAKE_PROGRAM_PATH ${CONAN_BIN_DIRS})
message(STATUS "Conan setup done. CMAKE_PROGRAM_PATH: ${CMAKE_PROGRAM_PATH}")

list(APPEND CMAKE_PROGRAM_PATH ${CONAN_BIN_DIRS})

  1. 对于LLVM来说,最好不能使用BUILD_SHARED_LIBS,因为LLVM依赖于全局数据,这些数据最终可能会在共享库之间复制可能会导致错误。也就是默认是static的。

  2. conan官方的一些包的recipe里面是把他们的一些cmake文件删除了,比如他的llvm-core只有一堆静态库,这就非常蛋疼了,想依赖这个lib去构建clang是不行的。所以还得自己打包。

  3. 默认的conan的build_folder就是同个目录,他都是打包结束后直接从当前文件夹下面选择性的去拷贝到package_folder下面。当然这个过程可以随便自定义,我觉得直接cmake install到package目录就完事了。

  4. 报错ConanException: llvm-core/12.0.0 package_info(): Package require 'libxml2' not used in components requires

    我用官方的llvm-core就有这个问题,我一开始一直以为是我的问题,然后发现他可能打包的时候就出问题了。conan的设计思路是每个package_info里面提供了每个库的详细信息,像llvm这种库,是由多个组件构成的,为了详细起见,他得把每个component的requires写清楚,所以llvm的打包脚本里面就先用cmake生成依赖关系,然后packeage info里面解析依赖关系添加依赖,这个问题的出现就是因为,明明整个库要求了libxml2,但是里面没有一个component去依赖这个库,那不就说明不需要依赖吗,所以直接报错。

    我找了一下发现libxml2是被LLVMWindowsManifest引用的,但是输出依赖信息:windowsmanifest ['support'] ,并没有添加这个依赖。目前猜想要么是patch没有打上,要么是依赖关系没有生成正确。

    还有就是他的component.json不知道是哪里弄出来的,cmake和conan的文档里面都没有写生成这个文件的地方。

  5. 如果直接include整个导出的llvm-core,会报错找不到一些动态链接库,然后我发现llvm官方打包的二进制里面是没有的。应该是conan生成package info的时候没有删除这些不需要的依赖。

  6. conan可以生成Conan find package,然后在cmake中调用find package可以找到对应的包

  7. 用打包出来的llvm-core去链接,一直报错找不到一个函数的定义(那个函数里面有个string),各种尝试才发现是conan自己生成的conan_basic_setup里面默认会从系统的profile中读取定义compiler.libcxx=libstdc++,然后设置-D_GLIBCXX_USE_CXX11_ABI=0。但是问题在于我也是用相同的编译器选项去编译llvm的,为什么生成的llvmlib却需要GLIBCXX_USE_CXX11_ABI=1呢?

    先用命令查看一下目前的编译器abi版本,发现默认是cxx11的

    gcc -v 2>&1 | sed -n 's/.*\(--with-default-libstdcxx-abi=new\).*/\1/p'
    --with-default-libstdcxx-abi=new
    在cmake中可以用如下命令查看添加了说明编译定义。
    get_directory_property( DirDefs COMPILE_DEFINITIONS )
    message( "COMPILE_DEFINITIONS = ${DirDefs}" )
    最后发现是我自己忘记在编译llvm的时候添加上conan basic setup了,导致没有指定。

  8. libxmls nanohttp.c:(.text+0x507): undefined reference to 'fcntl64'

    发现conan这东西出发点是好的,但是一定得需要把一个包所有的依赖全部展示清楚才好,上面这个问题就是预编译好的xml2需要的fcntl64包我的系统并没有。以后还是不要搞跨平台了,直接都用docker+linux完事了,没有环境问题。不然再怎么打包都会有奇怪的问题。。 这个问题估计是因为预编译的libxml2的版本ubuntu20的,但是我是ubuntu18的,所以重新编译安装xml2。

  9. LLVM ERROR: inconsistency in registered CommandLine options

    我不知道为啥编译出来的clang居然是动态链接的,而llvm是静态编译的,从而导致的问题。但是clang的cmake根本就不接受动态链接的编译配置啊,重新configure一下编译就解决了。。

  10. 利用cmake运行Conan,因为很多开发环境是不支持自动执行conan再cmake编译的,这样就不能提供自动补全、直接debug等功能了,所以需要自动化这个流程。但是我们要对开发的库进行conan打包的时候,又需要执行conan的命令,所以conan官方的解决方案是这里https://github.com/conan-io/cmake-conan,对cmake需要做以下修改:

    if(CONAN_EXPORTED) # in conan local cache
    # standard conan installation, deps will be defined in conanfile.py
    # and not necessary to call conan again, conan is already running
    include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
    conan_basic_setup()
    else() # in user space
    include(conan.cmake)
    # Make sure to use conanfile.py to define dependencies, to stay consistent
    conan_cmake_configure(REQUIRES fmt/6.1.2 GENERATORS cmake_find_package)
    conan_cmake_autodetect(settings)
    conan_cmake_install(PATH_OR_REFERENCE . BUILD missing REMOTE conan-center SETTINGS ${settings})
    endif()
  11. CONAN_PKG::xxxx这个是Conan setup时候的一个选项,如果添加了TARGETS的选项,使用Conan添加的lib都用统一的接口,但是这样其实不是很好,如果当前开发环境比较混乱的话(引用的包引用了conan的包,但是你只想直接调用,就会报错找不到CONAN_PKG::xxxx),所以要么都设置成相同的依赖,要么cmake里面再多写点。

  12. 想要正确的导出conan包,让他和原来的包一样使用,还是比较非常麻烦。比如halide,原始的halide中有个target叫Halide::Generator,他的属性中包含了GenGen.cpp这个文件。首先如果想在cmake中使用这个target,conan打包就需要把这个component明确导出,但是只要导出一个componet,你所有的requirs都得指定到对应的component。llvm中就是先分析依赖图,然后手动解析,构建出对应的component列表,然后在一个个字符串处理,找到对应的依赖、系统库依赖。上面的事情都做完了,你还是没办法使用conan导出的Halide::Generator,因为conan还不支持为component添加文件属性,真的无语了。