C++ project
centos7环境下使用
静态库和动态库:当我们需要把一些通用的功能封装起来,供以后调用的时候。在之前我们是将公用的部分提炼出来写在一个xxx.h和xxx.cpp文件中,然后在我们的主程序中引入xxx.h的头文件,然后再在编译的时候将主程序和xxx.cpp文件一起编译实现的。
在编译的时候其实有两个过程,首先会将主程序main.cpp和公用的xxx.cpp分别编译为两个二进制的文件,然后在链接在一起形成一个可执行文件。
上面的这种依赖其他的公用代码的方式在C++中可以通过将依赖编译为库的方式来引用。
编译出来的库又分为两种:静态库和动态库。
静态库:当我们将上面的公用的部分编译为一个静态库的时候,在使用这个静态库的时候编译器会将静态库和主程序代码一起链接打包到生成的可执行文件中去。这样生成的可执行文件可能就会比较臃肿,但是执行的时候比较快,而且由于将需要的东西都全部打包在一起了,这个执行文件的移植性就比较好。还有就是如果我们的库文件更新了,那么这个主程序就需要引入更新后的库文件重新打包。
静态库的生成和使用:
代码文件_public.h
#include <stdio.h>
void sayhello();
代码文件_public.cpp
#include "./_public.h"
void sayhello()
{
printf("hello~\n");
}
主程序文件:test.cpp
#include "./_public.h"
sayhello();
首先将_public.c编译成二进制的.o文件:g++ -c _public.cpp。完成后当前目录会生成一个_public.o的文件
通过ar工具将目标文件打包成.a静态库文件:ar -crv lib_public.a _public.o。完成后当前目录下会生成一个lib_public.a文件,这个文件就是静态库文件
将主程序文件和静态库文件一起打包生成可执行文件:g++ -o test test.cpp -L./ -l_public。-L用来指定静态库所在的目录,我们的静态库就在当前目录下所以直接用./。-l后面跟的是引用的静态库的名称(去除掉前面的lib和后缀.o)
然后./test执行生成的可执行文件test
动态库:动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入。不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题。动态库在程序运行是才被载入,也解决了静态库对程序的更新、部署和发布页会带来麻烦。用户只需要更新动态库即可,增量更新。
同样上上面的代码将其编译为共享库并调用的流程如下:
首先将_public.c编译成二进制的.o文件:g++ -fPIC -c _public.cpp。完成后当前目录会生成一个_public.o的文件,-fPIC 创建与地址无关的编译程序(pic,position independent code),是为了能够在多个应用程序间共享。
生成动态链接库.so文件:g++ -shared -o lib_public.so _public.o。完成后当前目录会生成一个lib_public.so文件,该文件就是生成的动态链接库。
生成可执行文件:g++ -o test1 test.cpp -L./ -l_public
将生成的lib_public.so文件拷贝到/usr/lib中,因为这个g++默认去寻找动态库的地址:cp lib_public.so /usr/lib/lib_public.so。
执行命令:ldconfig。这个命令用于更新动态库的列表以便能将我们新拷贝进去的库文件能被g++找到。
运行程序:./test1
参考地址:https://blog.csdn.net/kai_zone/article/details/93907101
使用cmake构建项目:
cmake安装:删除自带版本本yum remove cmake -y && rm -f /usr/bin/cmake,下载wget -c https://github.com/Kitware/CMake/releases/download/v3.14.2/cmake-3.14.2.tar.gz,解压tar xvf cmake-3.14.2.tar.gz && cd cmake-3.14.2/,安装(1)./bootstrap(2)gmake(3)gamek install,软链ln -s /usr/local/bin/cmake /usr/bin/,查看安装后的版本cmake --version。参考自:
https://blog.csdn.net/MaxWoods/article/details/89383362
用cmake编译一个简单的c++文件:
test1.cpp文件如下
#include "stdio.h"
int main()
{
printf("this is a test\n");
return 0;
}
当前目录下创建一个CMakeLists.txt内容如下:
# CMake 最低版本要求
cmake_minimum_required(VERSION 3.10.2)
# 项目信息
project(test)
# 指定生成目标,这里表示用当前目录下的test1.cpp编译生成的可执行文件为test。如果要一起编译多个.cpp文件直接空格后加在后面即可。
add_executable(test test1.cpp)
执行cmake .来生成makefile,然后用make执行生成的makefile,成功后就生成了可执行文件test,然后./test 运行生成的文件即可。
如果当前目录下面又很多的.cpp文件,都需要进行编译,如果将它们的名字全部一个个加到CMakeLists.txt文件中比较麻烦,可以使用下面的方式对当前目录下的全部文件进行编译:
# CMake 最低版本要求
cmake_minimum_required(VERSION 3.10.2)
# 项目信息
project(test)
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
# 指定生成目标
add_executable(test ${DIR_SRCS})
用cmake生成静态库:
将上面静态库的时候使用的test.cpp、_public.h和_public.cpp拷贝到当前目录下,生成CMakeLists.txt文件:
# 生成链接库
add_library (_public STATUC _public.cpp)
执行后就可以再当前目录下生成lib_public.a这个静态库文件
在test.cpp中引入这个静态库文件,CMakeLists.txt文件:
# CMake 最低版本要求
cmake_minimum_required(VERSION 3.10.2)
# 项目信息
project(test)
# 指定生成目标
add_executable(test test.cpp)
# 添加静态链接库,将当前目录下的_public链接到生成的可执行文件test中
target_link_libraries(test _public)
使用包含子目录的方式,将静态库放在子目录中,一次性用CMakeLists.txt生成可执行文件。在当前文件夹中新建一个subFile文件夹,将上个例子中的_public.h和_public.cpp和生成静态库的CMakeLists.txt移到这个子目录中,当前目录下是test.cpp、_public.h文件,在当前目录下生成一个CMakeLists.txt文件,内容如下:
# CMake 最低版本号要求
cmake_minimum_required (VERSION 3.10.2)
# 项目信息
project (test)
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
# 添加 subFile子目录,这个子目录中需要包含CMakeLists.txt文件,并会自动去执行那个CMakeLists.txt文件进行编译生成静态库。
add_subdirectory(subFile)
# 指定生成目标
add_executable(test test.cpp)
# 添加链接库
target_link_libraries(test _public)
在实际项目中,头文件可能不是和代码文件放在同一目录下面,这种情况可以用include_directories()的方式包含头文件的目录到cmake里面。测试文件如下:./_public.c,./CMakeLists.txt,./include/_public.h,./lib,
目的是_public.c包含include文件夹下的头文件,编译的静态库和动态库输出到lib文件夹下。
CMakeLists.txt文件内容如下:
# CMake 最低版本要求
cmake_minimum_required(VERSION 3.10.2)
# 项目信息
project(test)
#设置库文件的输出目录
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
#包含头文件目录进去
include_directories(include)
add_library (_publiclib STATIC _public.cpp)
add_library (_publicdll SHARED _public.cpp)
在上面的示例中生成库的操作都是和生成主程序的操作分开进行的,其实是可以将其放在同一个CMakeLists.txt种完成的。
测试文件如下:./src/_public.cpp,./src/test.cpp,./include/_public.h,./lib,./CMakeLists.txt
CMakeLists.txt文件内容如下:
# CMake 最低版本要求
cmake_minimum_required(VERSION 3.10.2)
# 项目信息
project(test)
#设置库文件的输出目录,${PROJECT_SOURCE_DIR}表示当前目录
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
#包含头文件目录进去
include_directories(include)
add_library (_publiclib SHARED src/_public.cpp)
#${PROJECT_NAME}等同于上面的project()中设置的值
add_executable(${PROJECT_NAME} src/test.cpp)
target_link_libraries(${PROJECT_NAME} _publiclib)
在CMakeLists.txt主程序调用外部的库的时候一般有一下几种方式:
(1)指定引用库的绝对路径
# CMake 最低版本要求
cmake_minimum_required(VERSION 3.10.2)
# 项目信息
project(test)
#${PROJECT_NAME}等同于上面的project()中设置的值
add_executable(${PROJECT_NAME} src/test.cpp)
target_link_libraries(${PROJECT_NAME} _publiclib)
//设置包的根路径为test_lib变量的值
set(test_lib /root/cmake-project/make5Dir)
#包含头文件目录进去
include_directories(${test_lib}/include)
add_executable(${PROJECT_NAME} src/test.cpp)
target_link_libraries(${PROJECT_NAME} ${test_lib}/lib/lib_publiclib.a)
(2)在生成库的时候就将库文件和头文件使用installl的方式安装到/usr中,使用库的时候就直接从其中进行引用。
将_public.h和_public.cpp文件放在当前目录下,使用cmake的方式将头文件和编译的静态库安装到/usr/include和/usr/lib下面,CMakeLists.txt文件内容如下:
# CMake 最低版本要求
cmake_minimum_required(VERSION 3.10.2)
# 项目信息
project(test1)
#生成静态库
add_library(_public1 STATIC _public1.cpp)
#设置CMAKE_INSTALL_PREFIX变量,该变量会作为安装的目录的前缀
set(CMAKE_INSTALL_PREFIX /usr)
#打印CMAKE_INSTALL_PREFIX变量的值
#message(${CMAKE_INSTALL_PREFIX})
#将当前目录下的_public.h文件安装到usr/include中
install(FILES ./_public1.h DESTINATION include)
#将生成的静态库安装到usr/lib下面
install(TARGETS _public1 ARCHIVE DESTINATION lib)
执行命令:cmake , make install。后_public.h和lib_public.a文件会安装到指定的目录中。
然后test.cpp中引用上面安装的库,CMakeLists.txt文件如下:
cmake_minimum_required(VERSION 3.10.1)
project(test2)
#包含的头文件目录
include_directories(/usr/include)
add_executable(${PROJECT_NAME} test.cpp)
//添加链接库的目录
target_link_libraries(${PROJECT_NAME} /usr/lib/lib_public1.a)
(3)使用find_package()的方式导入库
生成自己的find_package可用模块:
文件结构:./_public2.h,./_public2.cpp,./CMakeLists.txt,./Find_public2.cmake
Find_public2.cmake内容:
#从/usr/include/下找到_public2.h文件,路径赋值给_public2_INCLUDE_DIR
find_path(_public2_INCLUDE_DIR NAMES _public2.h PATHS "/usr/include/")
#从/usr/lib/下找到_public2.cpp文件,路径赋值给_public2_LIBRARY
find_library(_public2_LIBRARY NAMES _public2 PATHS "/usr/lib/")
#如果两个都找了就给变量_public2_FOUND赋值为True
IF (_public2_INCLUDE_DIR AND _public2_LIBRARY)
SET(_public2_FOUND TRUE)
ENDIF (_public2_INCLUDE_DIR AND _public2_LIBRARY)
#如果_public2_FOUND为真
IF (_publi2_FOUND)
#如果是QUIETLY,模式,没有找到包就出现提示信息并不中断程序
IF (NOT public2_FIND_QUIETLY)
MESSAGE(STATUS "Found _public2:${_public2_LIBRARY}")
ENDIF (NOT public2_FIND_QUIETLY)
ELSE (_publi2_FOUND)
#如果是REQUIRED,模式,没有找到包则中断程序并提示信息
IF (public2_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "could not find _public2 library")
ENDIF (public2_FIND_REQUIRED)
ENDIF (_publi2_FOUND)
CMakeLists.txt文件内容:
cmake_minimum_required(VERSION 3.10.2)
project(test3)
#生成静态库
add_library(_public2 STATIC _public2.cpp)
#set(CMAKE_MODULE_PATH /usr/local/share/cmake-3.14/Modules)
#设置install的默认目录
set(CMAKE_INSTALL_PREFIX /usr)
#将cmake文件,.h文件,.cpp文件安装到设置的目录下
install(FILES Find_public2.cmake DESTINATION /usr/local/share/cmake-3.14/Modules/)
install(FILES _public2.h DESTINATION include)
install(TARGETS _public2 ARCHIVE DESTINATION lib)
在源程序中引用上面自己的模块:
文件结构:./test.cpp ./CMakeLists.txt
CMakeLists.txt内容:
cmake_minimum_required(VERSION 3.10.2)
project(test)
#set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/lib/cmake/)
#使用REQUIRED的方式加载_public2包,相当于去找上面的Find_public2.cmake文件
find_package(_public2 REQUIRED)
#判断_public2_FOUND的值来确定是否找到头文件和库文件是否找到
if(_public2_FOUND)
#包含_public_INCLUDE_DIR变量指代的头文件
include_directories(${_public_INCLUDE_DIR})
add_executable(${PROJECT_NAME} test.cpp)
#包含_public2_LIBRARY变量指代的库文件
target_link_libraries(${PROJECT_NAME} ${_public2_LIBRARY})
else(_public2_FOUND)
message(FATAL_ERROR "_public2 library not found")
endif(_public2_FOUND)