目录
1.概述
2.文件结构和内容
3.使用方法和效果
一.概述
本文章将讲述 一个简单的模型 :通过cmake构建工程,其中包括一个专门用来导出dll或so动态库的工程,一个专门用来调用动态库的工程。并且能跨平台运行。
涉及c++ 函数 __attribute__ 和 __declspec 的使用,这两函数可以声明头文件的函数是用来导出成动态库或者调用动态库
二.文件结构和内容
文件结构为
CMakeLists.txt
│
├─basicFun
│ basicFun.cpp
│ basicFunApi.h
│ CMakeLists.txt
│
└─exctueMain
│ CMakeLists.txt
│ exctueMain.cpp
│
├─testDir1
│ test1.cpp
│ test1.h
│
└─testDir2
test2.cpp
test2.h
1.总cmake
# 以下是 ./CMakeLists.txt 的内容
# 以下是 ./CMakeLists.txt 的内容
cmake_minimum_required(VERSION 3.10)
project(my_proj)
#父cmakeList文件定义的变量可以传递到 子cmakeList中
set(PROJECT_TOP_DIR ${CMAKE_SOURCE_DIR})
MESSAGE( STATUS "PROJECT_TOP_DIR = ${PROJECT_TOP_DIR}.")
#父母cmake定义的宏,到孩子cmake里的工程也生效
add_definitions(-DTEST_HONG)
if(${CMAKE_HOST_SYSTEM_NAME} MATCHES "Linux")
add_definitions(-DSYSTEM_IS_LINUX)
endif()
if(${CMAKE_HOST_SYSTEM_NAME} MATCHES "Windows")
add_definitions(-DSYSTEM_IS_WINDOWS)
endif()
#get_filename_component(PROJECT_TOP_DIR ${CMAKE_SOURCE_DIR} DIRECTORY)
#上面函数参数3是 DIRECTORY
#如果参数2是个文件夹,那么结果参数1就是参数2文件夹的父母文件夹
#如果参数2是个文件 ,那么结果就是参数2所在的文件夹
#将生成的lib dll 可执行文件放在同一个目录
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
add_subdirectory(${CMAKE_SOURCE_DIR}/basicFun basicFun.out)
add_subdirectory(${CMAKE_SOURCE_DIR}/exctueMain exctueMain.out)
2.basicFun工程
# 以下是 ./basicFun/CMakeLists.txt 的内容
# 以下是 ./basicFun/CMakeLists.txt 的内容
#在此处定义c++工程宏定义 DCOMMONFUN_EXPORT
#当在工程basicFun时,此宏定义生效
#当处于其他工程时,此宏定义不存在
#通过这个方式使该工程既可以生成dll又可以被调用dll
#此宏在对外接口的.h头文件中·被使用 COMMONFUN_EXPORT
add_definitions(-DCOMMONFUN_EXPORT)
cmake_minimum_required(VERSION 3.10)
set(CMAKE_CXX_STANDARD 17) # 设置c++版本为c++17
file(GLOB File_Source
basicFun.cpp
basicFunApi.h
)
project(BasicFun)
add_library(BasicFun SHARED
${File_Source}
)
# 以下是 ./basicFun/basicFunApi.h 的内容
// 以下是 ./basicFun/basicFunApi.h 的内容
#ifndef BASICFUNAPI_H
#define BASICFUNAPI_H
#include <iostream>
#include <vector>// 系统自带的宏 linux, 在cmake里自定义的 SYSTEM_IS_LINUX。都可以识别到
#ifdef SYSTEM_IS_LINUX
#define BASICFUN_API __attribute__((visibility("default")))
#endif
// 系统自带的宏 _MSC_VER _WIN32, 在cmake里自定义的 SYSTEM_IS_WINDOWS。都可以识别到
#ifdef SYSTEM_IS_WINDOWS
#ifdef COMMONFUN_EXPORT
#define BASICFUN_API __declspec(dllexport)
#else
#define BASICFUN_API __declspec(dllimport)
#endif
#endifnamespace nsCommonFun {
BASICFUN_API void printNumber(int a);#ifdef TEST_HONG
BASICFUN_API void ProveHong();
#endif
}#endif
# 以下是 ./basicFun/basicFun.cpp 的内容
// 以下是 ./basicFun/basicFun.cpp 的内容
#include "basicFunApi.h"
namespace nsCommonFun {
#ifdef TEST_HONG
void ProveHong() {
std::cout << "basicFun: TEST_HONG exists" << std::endl;
}
#endif
void printNumber(int a) {
std::cout << "number == " << a << std::endl;
#ifdef TEST_HONG
ProveHong();
#endif
}
}
3.excuteMain工程部分
# 以下是 ./excuteMain/CMakeLists.txt 的内容
# 以下是 ./excuteMain/CMakeLists.txt 的内容
cmake_minimum_required(VERSION 3.10)
project(exctueMain)
set(CMAKE_CXX_STANDARD 17) # 设置c++版本为c++17
#GLOB_RECURSE 递归地去搜索设定目录下的文件
file(GLOB_RECURSE SUB_FILES
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/*.h
)
add_executable(exctueMain ${SUB_FILES})
# PROJECT_TOP_DIR 从父母cmakeList传过来的变量
include_directories(${PROJECT_TOP_DIR}/basicFun)
target_link_libraries(exctueMain BasicFun)
MESSAGE( STATUS "systemType = ${CMAKE_HOST_SYSTEM_NAME}.")
#链接pthread库,否则在linux下std::thread无法使用
if(${CMAKE_HOST_SYSTEM_NAME} MATCHES "Linux")
target_link_libraries (exctueMain pthread)
endif()
# 以下是 ./excuteMain/exctueMain.cpp 的内容
#include "basicFunApi.h"
#include "testDir1/test1.h"
#include "testDir2/test2.h"
int main() {
#ifdef TEST_HONG
std::cout << "exctue main , TEST_HONG exist" << std::endl;
#endif
nsCommonFun::printNumber(100);
Test1Thread();
Test2();
}
# 以下是 ./testDir1/test1.h 的内容
#include <iostream>
#include <vector>
#include <thread>
void LoopAdd();
void Test1Thread();
# 以下是 ./testDir1/test1.cpp 的内容
#include "test1.h"
const int loopTime = 200;
void LoopAdd() {
int res = 0;
for (int i = 0; i < loopTime; i++) {
res += i;
}
}
void Test1Thread() {
std::vector<std::shared_ptr<std::thread>> vecThread;
for (int i = 0; i < loopTime; i++) {
std::shared_ptr<std::thread> th1 = std::make_shared<std::thread>(LoopAdd);
vecThread.push_back(th1);
}
for (auto& tempTh : vecThread) {
tempTh->join();
}
std::cout << "Test1 Thread" << std::endl;
}
# 以下是 ./testDir2/test2.h 的内容
#include <iostream>
void Test2();
# 以下是 ./testDir2/test2.cpp 的内容
#include "test2.h"
void Test2() {
std::cout << "Test2" << std::endl;
}
三.使用方法和效果
打开控制台或终端 进入主目录。
如果是windows也可以直接用界面的cmake构建vs工程,在vs中编译。
1.输入命令 cmake .
构建cmake工程
2.输入命令 cmake --build .
编译完工程 basicFun 和 exctueMain
3.进入到 主目录/lib中 执行可执行文件文件 exctueMain。
VS2022工程中展示的工程结构如下图
四.讲解和其他
在cmake中 cmake变量值如下所示
# 在 Linux 平台
CMAKE_HOST_SYSTEM_NAME = "Linux"
CMAKE_HOST_UNIX = 1
CMAKE_HOST_WIN32 = 空
UNIX = 1
WIN32 = 空
# 在 Windows 平台
CMAKE_HOST_SYSTEM_NAME = "Windows"
CMAKE_HOST_UNIX = 空
CMAKE_HOST_WIN32 = 1
UNIX = 空
WIN32 = 1
关于识别cmake是在windows还是在linux可以查看这个链接