IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C/C++开发之CMakeList(其二) -> 正文阅读

[C++知识库]C/C++开发之CMakeList(其二)

嵌套式CMakeLists写法,文件结构如下:

   |--examples
   |   |--add_example.c
   |   |--sub_example.c
   |--CMakeLists.txt
   |--add
   |   |--add.c
   |   |--add.h
   |--sub
   |   |--sub.c
   |   |--sub.h

文件内容详情见C/C++开发之CMakelist(其一)
将C/C++开发之CMakeList(其一)的内容推广,我们可以将对应文件相对路径分别记录,再统一编译运行
需要注意添加include_directories,指定include目录,否则在add.c与sub.c中可能找不到头文件。

#最小cmake版本
cmake_minimum_required(VERSION 2.8)
#项目名字,随意起
project(simple_exe)
#设置C/c++版本(如c99,c++11,c++17等版本),下面表示使用c99版本
set(CMAKE_C_STANDARD 99)

#指定include路径
#${CMAKE_CURRENT_SOURCE_DIR}表示当前文件目录,是cmake内置变量
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/add/)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/sub/)

#set作用为将第一个字符之后的字符命名为第一个字符,
#下面的例子表示将add.c与sub.c用SOURCES表示,即SOURCES = [add.c, sub.c]
set(SOURCES
    add/add.c
    sub/sub.c
)
#将可执行文件统一命名为MAIN_FILES
set(MAIN_FILES
    examples/add_example.c
    examples/sub_example.c
)
#将文件打包成alg库,中间的选项STATIC表示静态库,${SOURCES}为源文件,alg为生成的静态库名字
add_library(alg STATIC ${SOURCES})

#循环MAIN_FILES中的每一个元素
foreach(mainfile ${MAIN_FILES})
  #获取不带文件后缀的文件名,下面的作用为提取add_example与sub_example
  get_filename_component(mainname ${mainfile} NAME_WE)
  #将mainfile编译生成可执行文件mainname
  add_executable(${mainname} ${mainfile})
  #将静态库链接到可执行文件中
  target_link_libraries(${mainname} alg)
endforeach()

但是头文件过多时,写起来不方便,用户调用也不方便,最好的方式是将所有头文件整合到一起,统一加到alg.h中,文件结构如下:

   |--examples
   |   |--add_example.c
   |   |--sub_example.c
   |--CMakeLists.txt
   |--add
   |   |--add.c
   |--sub
   |   |--sub.c
   |--include
   |   |--alg.h

头文件alg.h:

#ifndef __ALG_H
#define __ALG_H

int my_sub(int a, int b);
int my_add(int a, int b);

#endif

源文件add.c,sub.c
add.c

#include "alg.h"

int my_add(int a, int b){
    return a + b;
}

sub.c

#include "alg.h"

int my_sub(int a, int b){
    return a - b;
}

main文件sub_example.c, add_example.c
add_example.c

#include "alg.h"
#include<stdio.h>

int main(){
    int a = 1, b = 2;
    printf("add:%d\n", my_add(a, b));
    return 0;
}

sub_example.c

#include "alg.h"
#include<stdio.h>

int main(){
    int a = 1, b = 2;
    printf("sub:%d\n", my_sub(a, b));
    return 0;
}

对应cmake也需要改写include_directories

#最小cmake版本
cmake_minimum_required(VERSION 2.8)
#项目名字,随意起
project(simple_exe)
#设置C/c++版本(如c99,c++11,c++17等版本),下面表示使用c99版本
set(CMAKE_C_STANDARD 99)

#指定include目录
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/)

#set作用为将第一个字符之后的字符命名为第一个字符,
#下面的例子表示将add.c与sub.c用SOURCES表示,即SOURCES = [add.c, sub.c]
set(SOURCES
    add/add.c
    sub/sub.c
)
#将可执行文件统一命名为MAIN_FILES
set(MAIN_FILES
    examples/add_example.c
    examples/sub_example.c
)
#将文件打包成alg库,中间的选项STATIC表示静态库,${SOURCES}为源文件,alg为生成的静态库名字
add_library(alg STATIC ${SOURCES})

#循环MAIN_FILES中的每一个元素
foreach(mainfile ${MAIN_FILES})
  #获取不带文件后缀的文件名,下面的作用为提取add_example与sub_example
  get_filename_component(mainname ${mainfile} NAME_WE)
  #将mainfile编译生成可执行文件mainname
  add_executable(${mainname} ${mainfile})
  #将静态库链接到可执行文件中
  target_link_libraries(${mainname} alg)
endforeach()

如果源文件也特别多,文件夹里面也嵌套了很多文件夹,将文件中所有目录全写入最外层CMakeLists显得特别混乱,不利于团队开发。解决方案为在合适的文件嵌套深度写CMakelists.txt文件,然后将内部的CMakelists.txt文件中的变量层层传入外部合适的位置。不慌,看案例:
我们再增加一层目录,如下

   |--examples
   |   |--add_example.c
   |   |--sub_example.c
   |--CMakeLists.txt
   |--include
   |   |--alg.h
   |--alg
   |   |--add
   |   |   |--add.c
   |   |   |--CMakeLists.txt
   |   |--sub
   |   |   |--sub.c
   |   |   |--CMakeLists.txt
   |   |--CMakeLists.txt

alg/add/CMakeLists.txt中重点为set(SRCS ${SRCS} ${SOURCES} PARENT_SCOPE),表示作用域在父目录

#老三段
cmake_minimum_required(VERSION 2.8)
project(simple_alg_exe)
set(CMAKE_C_STANDARD 99)
#注意这里的目录不是相对路径,是从可执行CMakeLists.txt开始的(即存在add_library或add_executable的CMakeLists,如果写错的话会报错找不到改文件,可以考虑修改一下子目录里面的CMakeLists中SOURCES的目录)
set(SOURCES
  alg/add/add.c
)

#等价于SRC = [SRC, SOURCES],PARENT_SCOPE表示作用域为父目录
#注意这里为啥不写成set(SOURCES ${SOURCES} ${SOURCES} PARENT_SCOPE),注意到第8行的set(SOURCES ...)
#如果写成这种形式,如果在其它层也存在SOURCES,那么在第八行SOURCES会被替换成[add/add.c, sub/sub.c]导致找不到部分源文件
#所以在该项目里我们约定SRCS为全局变量,提供给外层使用,SOURCES仅在本层使用
set(SRCS ${SRCS} ${SOURCES} PARENT_SCOPE)

alg/sub/CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
project(simple_alg_exe)
set(CMAKE_C_STANDARD 99)

set(SOURCES
  alg/sub/sub.c
)
set(SRCS ${SRCS} ${SOURCES} PARENT_SCOPE)

alg/CMakeLists.txt如下,重点为add_subdirectory,表示调用子目录的CMakeLists:

cmake_minimum_required(VERSION 2.8)
project(simple_alg_exe)
set(CMAKE_C_STANDARD 99)

#将文件夹内存在CMakelist的所有文件命名为MODULES
set(MODULES
  add
  sub
)

foreach(module ${MODULES})
  #执行每一个文件夹里面的CMakeLists.txt脚本
  add_subdirectory(${module})
endforeach()
#将SRC传入上层,这样可以层层上传子文件夹中CMakeLists里的变量。
set(SRCS ${SRCS} PARENT_SCOPE)

CMakeLists.txt如下:

#最小cmake版本
cmake_minimum_required(VERSION 2.8)
#项目名字,随意起
project(simple_exe)
#设置C/c++版本(如c99,c++11,c++17等版本),下面表示使用c99版本
set(CMAKE_C_STANDARD 99)

#指定include目录
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/)

#将文件夹内存在CMakelist的所有文件命名为MODULES
set(MODULES
  alg
)

foreach(module ${MODULES})
  #执行每一个文件夹里面的CMakeLists.txt脚本
  add_subdirectory(${module})
endforeach()
#将可执行文件统一命名为MAIN_FILES
set(MAIN_FILES
    examples/add_example.c
    examples/sub_example.c
)
#将文件打包成alg库,中间的选项STATIC表示静态库,${SOURCES}为源文件,alg为生成的静态库名字
add_library(alg STATIC ${SRCS})

#循环MAIN_FILES中的每一个元素
foreach(mainfile ${MAIN_FILES})
  #获取不带文件后缀的文件名,下面的作用为提取add_example与sub_example
  get_filename_component(mainname ${mainfile} NAME_WE)
  #将mainfile编译生成可执行文件mainname
  add_executable(${mainname} ${mainfile})
  #将静态库链接到可执行文件中
  target_link_libraries(${mainname} alg)
endforeach()

但是!!!如果main示例文件过多而且也存在各种文件嵌套,怎么办?
修改文件目录如下:

   |--examples
   |   |--add_example.c
   |   |--sub_example.c
   |   |--CMakeLists.txt
   |--CMakeLists.txt
   |--include
   |   |--alg.h
   |--alg
   |   |--add
   |   |   |--add.c
   |   |   |--CMakeLists.txt
   |   |--sub
   |   |   |--sub.c
   |   |   |--CMakeLists.txt
   |   |--CMakeLists.txt
   |--build

examples/CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
project(simple_exe)
set(CMAKE_C_STANDARD 99)

#将可执行文件统一命名为MAIN_FILES
set(MAIN_FILES
    add_example.c
    sub_example.c
)

#循环MAIN_FILES中的每一个元素
foreach(mainfile ${MAIN_FILES})
  #获取不带文件后缀的文件名,下面的作用为提取add_example与sub_example
  get_filename_component(mainname ${mainfile} NAME_WE)
  #将mainfile编译生成可执行文件mainname
  add_executable(${mainname} ${mainfile})
  #将静态库链接到可执行文件中
  target_link_libraries(${mainname} alg)
endforeach()

alg/add/CMakeLists.txt

#老三段
cmake_minimum_required(VERSION 2.8)
project(simple_alg_exe)
set(CMAKE_C_STANDARD 99)
#对比一下上一节SOURCES的写法
set(SOURCES
  add/add.c
)

set(SRCS ${SRCS} ${SOURCES} PARENT_SCOPE)

alg/sub/CMakeLists.txt

#老三段
cmake_minimum_required(VERSION 2.8)
project(simple_alg_exe)
set(CMAKE_C_STANDARD 99)

set(SOURCES
  sub/sub.c
)

set(SRCS ${SRCS} ${SOURCES} PARENT_SCOPE)

alg/CMakeLists.txt,重点理解一下SET(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/…/lib)

cmake_minimum_required(VERSION 2.8)
project(simple_alg_exe)
set(CMAKE_C_STANDARD 99)

#设置LIBRARY_OUTPUT_PATH为库的输出位置
SET(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../lib) 

#将文件夹内存在CMakelist的所有文件命名为MODULES
set(MODULES
  add
  sub
)

foreach(module ${MODULES})
  #执行每一个文件夹里面的CMakeLists.txt脚本
  add_subdirectory(${module})
endforeach()

#将文件打包成alg库,中间的选项STATIC表示静态库,${SOURCES}为源文件,alg为生成的静态库名字
add_library(alg STATIC ${SRCS})

CMakeLists.txt

#最小cmake版本
cmake_minimum_required(VERSION 2.8)
#项目名字,随意起
project(simple_exe)
#设置C/c++版本(如c99,c++11,c++17等版本),下面表示使用c99版本
set(CMAKE_C_STANDARD 99)

#指定include目录,作用域为全局,包括子目录中的CMakeLists
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/)
#指定静态库输出路径,作用域为全局,包括子目录中的CMakeLists
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/lib)

#将文件夹内存在CMakelist的所有文件命名为MODULES
set(MODULES
  alg
  examples
)

foreach(module ${MODULES})
  #执行每一个文件夹里面的CMakeLists.txt脚本
  add_subdirectory(${module})
endforeach()

查看一下编译之后的文件目录,对比一下编译之前的目录

   |--examples
   |   |--add_example.c
   |   |--sub_example.c
   |   |--CMakeLists.txt
   |--CMakeLists.txt
   |--include
   |   |--alg.h
   |--alg
   |   |--add
   |   |   |--add.c
   |   |   |--CMakeLists.txt
   |   |--sub
   |   |   |--sub.c
   |   |   |--CMakeLists.txt
   |   |--CMakeLists.txt
   |--lib
   |   |--libalg.a

还差一步就可以打包发布自己的程序啦,回忆一下我们源码安装c/c++程序时,离不开这几个命令,cmake, make , make install。目前我们仅仅在使用cmake, make之后在build/examples里面可以找到自己的源码,所以如何使用make install呢?
make install发布自己的程序
只需要替换上一节中alg/CmkaeLists.txt的内容如下,注意Install命令

#老三段
cmake_minimum_required(VERSION 2.8)
project(simple_alg_exe)
set(CMAKE_C_STANDARD 99)

#设置LIBRARY_OUTPUT_PATH为库的输出位置
SET(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../lib) 

#将文件夹内存在CMakelist的所有文件命名为MODULES
set(MODULES
  add
  sub
)

foreach(module ${MODULES})
  #执行每一个文件夹里面的CMakeLists.txt脚本
  add_subdirectory(${module})
endforeach()

#将文件打包成alg库,中间的选项STATIC表示静态库,${SOURCES}为源文件,alg为生成的静态库名字
add_library(alg STATIC ${SRCS})

#将alg.h头文件发布到${CMAKE_CURRENT_SOURCE_DIR}/../output/include目录中,当然可以写一些其它的目录,如/usr/local/lib64/include
install(FILES ../include/alg.h DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/../output/include)
#将libalg.a静态库文件发布到${CMAKE_CURRENT_SOURCE_DIR}/../output/lib目录中
install(FILES ../lib/libalg.a DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/../output/lib)

当输入make install时输出如下:

 make install
[ 42%] Built target alg
[ 71%] Built target sub_example
[100%] Built target add_example
Install the project...
-- Install configuration: ""
-- Installing: /home/lichangshi/ML2/my_test/test_cmake/alg/../output/include/alg.h
-- Installing: /home/lichangshi/ML2/my_test/test_cmake/alg/../output/lib/libalg.a

安装成功,查看目录结构

   |--examples
   |   |--add_example.c
   |   |--sub_example.c
   |   |--CMakeLists.txt
   |--CMakeLists.txt
   |--include
   |   |--alg.h
   |--alg
   |   |--add
   |   |   |--add.c
   |   |   |--CMakeLists.txt
   |   |--sub
   |   |   |--sub.c
   |   |   |--CMakeLists.txt
   |   |--CMakeLists.txt
   |--output
   |   |--lib
   |   |   |--libalg.a
   |   |--include
   |   |   |--alg.h
   |--lib
   |   |--libalg.a

安装成功,其它程序只要正确找到对应的头文件与静态库就可以直接调用自己的程序。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-17 21:52:22  更:2022-03-17 21:55:55 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 2:30:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码