整整搞了我两天。之前简单的程序以及静态库交叉编译都成功了,我还沾沾自喜,没想到一涉及到大型项目,多重调用就GG。淦!
来说正题~
手上的一个项目,有多个模块,每个模块有一堆类组成,这个模块还调用好多个静态库/动态库。需求是要把这个模块编译后也生成静态库来供一个main.exe调用。哦忘了,这一系列操作都是要交叉编译环境下的。交代完毕。
传送门
这里提醒一下,有两点比较注意。
host和target参数,内容一致, 必须确认和你的arm交叉编译工具链的前缀是一样的!而不是简简单单的arm-linux就可以。 比如我自己因为这个原因,重新编译了一下。 改成了arm-linux-gnueabihf
这个错误就是我第一次编译生成的库和其他生成的库不是一个编译器,导致无法识别该库。
修改–prefix参数,换一个路径就可以。
传送门
贴上CMakeLists.txt内容:
# CMake最低版本要求
cmake_minimum_required(VERSION 2.8)
# 设置目标系统
set(CMAKE_SYSTEM_NAME Linux)
set(USER_PATH "/home/gcc-linaro-arm-linux-gnueabihf-4.7-2013.03-20130313_linux")
# 设置工具链目录
set(tools ${USER_PATH}/bin/arm-linux-gnueabihf-g++)
# 设置编译器位置
set(CMAKE_C_COMPILER ${USER_PATH}/bin/arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER ${USER_PATH}/bin/arm-linux-gnueabihf-g++)
set(CMAKE_CROSSCOMPILING TRUE)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_FIND_ROOT_PATH ${USER_PATH})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
# 项目信息
project(DataCollect)
# C++11支持
add_definitions(-std=c++11)
add_definitions(-D_GLIBCXX_USE_NANOSLEEP)
set(CMAKE_CXX_FLAGS "${CAMKE_CXX_FLAGS} -pthread")
# 定义头文件和源文件路径
# 添加头文件路径
include_directories(/usr/include)
include_directories(${CMAKE_CURRENT_LIST_DIR}/../include)
aux_source_directory(${CMAKE_CURRENT_LIST_DIR} source_path)
# 指定生成路径
set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_LIST_DIR}/../lib)
#添加链接库路径
link_directories(/home/libzmq-master/arm-zeromq/lib)
# 生成静态库
add_library(${PROJECT_NAME} ${source_path})
target_link_libraries(${PROJECT_NAME} libpthread.a)
find_package(Threads)
target_link_libraries(${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/../lib/libhelper.a)
target_link_libraries(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/../lib/libscanhandler.a)
target_link_libraries(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/../lib/libtinyxml.a)
target_link_libraries(${PROJECT_NAME} libzmq -ldl)
# 显式指定编译器
#set(CMAKE_CXX_COMPILER "g++")
# 开启调试信息
set(CMAKE_BUILD_TYPE "Debug")
set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g2 -ggdb")
set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")
# 开启所有警告
set(CMAKE_CXX_FLAGS "-Wall")
对于以上内容,这里做几点解释:
- 设置目标系统,设置工具链目录,设置编辑器位置3项使用的前提都是要交叉编译的情况。如果只是在linux下编译运行,这些统统不要写。
- 另外,交叉编译写了上面三项,下方的显式指定编译器那一行也就不需要了,反之就需要显式指定。
- 对于添加C++11支持,建议按我写的那三项都写全了,少了可能会出问题。
以及 导入链接库
我在自己上述CMakeLists.txt文件里链接静态库用了两种方式:
① 直接 target_link_libraries,语法是
target_link_libraries(自己的项目名 引用的lib库的相对路径及名称)
target_link_libraries(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/../lib/libhelper.a)
②在指定生成静态库或者生成可执行程序那一行之前,先定义好链接库路径,然后再使用target_link_libraries。
#添加链接库路径
link_directories(/home/libzmq-master/arm-zeromq/lib)
target_link_libraries(${PROJECT_NAME} libzmq -ldl)
注意! 必须在add_library()或者add_executable()之前定义,不然不起作用。
使用第二种方式时,在target_link_libraries可以不必写xxx.a或xxx.so,即不加后缀。
这里贴一下生成静态库和可执行程序的不同的两行内容:
# 指定生成路径
set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_LIST_DIR}/../lib)
# 生成静态库
add_library(${PROJECT_NAME} ${source_path})
# 指定生成目标,引用source_path变量
add_executable(${PROJECT_NAME} ${source_path})
# 指定生成目录
SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_LIST_DIR}/../../bin)
# CMake最低版本要求
cmake_minimum_required(VERSION 2.8)
# 设置目标系统
set(CMAKE_SYSTEM_NAME Linux)
set(USER_PATH "/home/gcc-linaro-arm-linux-gnueabihf-4.7-2013.03-20130313_linux")
# 设置工具链目录
set(tools ${USER_PATH}/bin/arm-linux-gnueabihf-g++)
# 设置编译器位置
set(CMAKE_C_COMPILER ${USER_PATH}/bin/arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER ${USER_PATH}/bin/arm-linux-gnueabihf-g++)
set(CMAKE_CROSSCOMPILING TRUE)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_FIND_ROOT_PATH ${USER_PATH})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
# 项目信息
project(MainData)
# C++11支持
add_definitions(-std=c++11)
add_definitions(-D_GLIBCXX_USE_NANOSLEEP)
set(CMAKE_CXX_FLAGS "${CAMKE_CXX_FLAGS} -pthread")
# 定义头文件和源文件路径
# 添加头文件路径
include_directories(/usr/include)
include_directories(${CMAKE_CURRENT_LIST_DIR}/../include)
aux_source_directory(${CMAKE_CURRENT_LIST_DIR} source_path)
# 指定生成路径
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_LIST_DIR}/../Bin)
#引入链接库目录
link_directories(${CMAKE_CURRENT_LIST_DIR}/../lib)
link_directories(/home/libzmq-master/arm-zeromq/lib)
# 生成程序
add_executable(${PROJECT_NAME} ${source_path})
#链接库
#target_link_libraries(${PROJECT_NAME} libpthread.a)
find_package(Threads)
target_link_libraries(${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries(${PROJECT_NAME}
libDataCollect.a -ldl
libhelper.a -ldl
libscanhandler.a -ldl
libtinyxml.a -ldl
)
target_link_libraries(${PROJECT_NAME}
libzmq.so -ldl)
# 开启调试信息
set(CMAKE_BUILD_TYPE "Debug")
set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g2 -ggdb")
set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")
# 开启所有警告
set(CMAKE_CXX_FLAGS "-Wall")
这个文件和上一个文件内容不同的地方在:
调用外部链接库不仅调用了libDataCollect.a(生成静态库的该项目模块),还调用了它生成所依赖的库。即所有依赖的库都要链接到这里来。他们有个顺序,越是基础的越往下面放,这里libDataCollect.a在第一个位置,其余的都在后面。
另外,第一个文件里有了 libthread.a(linux系统调用的库),这里就不需要再写了,否则会出现错误:
我注释掉以后就正常编译了。
有问题的小伙伴欢迎评论留言,一起进步。:)