cmake编译多个工程,一个执行工程调用dll工程。跨平台 win和Linux。 __declspec __attribute__ 函数导出导入动态库声明

目录

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
#endif

namespace 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可以查看这个链接

跨平台CMake判断当前平台是Linux还是Windows_cmake判断操作系统_难搞哦~的博客-优快云博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值