• 发文
  • 评论
  • 微博
  • 空间
  • 微信

Cmake学习总结(三)

TXP嵌入式 2020-07-13 09:09 发文


cmake学习总结(一)

Cmake学习总结(二)

关于动态库和静态库的概念:

c语言里面静态链接库的制作和使用

c语言里面静态链接库的制作和使用



大家好,在上一篇文Cmake文章里面,我们同样在文章的最后面留了一个问题实现,就是把源文件放到src目录下,把头文件放到include目录下去,这样也比较符合别人和自己日后去配置工程(一看到这两个目就能知道啥意思了,清晰明了),同时在linux环境下生成的elf文件放到bin目录下;不过在文章发出去了几天,后面有网友又有提出了一些新的需求:

image

(如果网友有啥实际需要,可以私聊我,只要在我自身能力之内,我都可以写成文章出来分享给大家)熟悉我的网友都知道,我也是小白,会从很基础的东西开始分享开始,虽然都是比较理论化的东西,但是都是点滴的积累(有的时候,其实你真正在有些项目开发过程中,学到的东西不是很多,更多的是依靠平时的基础积累加以扩展,所以总的来说,平时的折腾还是非常值得!);同时有啥比较实际一点的需求咋也慢慢深入,一步步来,稳扎稳打,知识性的东西来不得半点虚假和马虎。好了,开始进入主题分享了:

一、src、include、bin目录的使用(更加正规化):

1、先开始创建这三个目录结构,并把相应的文件放入进去:

root@txp-virtual-machine:/home/txp/testmy# mkdir bin build src include
root@txp-virtual-machine:/home/txp/testmy# ls
bin  build  include  src

include目录下文件放入(这里test1.h和test2.h的内容是接续前面的文章里面的内容,这里我就不再造轮子了):

root@txp-virtual-machine:/home/txp/testmy/include# ls
test1.h  test2.h

src目录下文件放入(这里test1.c和test2.c的内容是接续前面的文章里面的内容,这里我就不再造轮子了):

root@txp-virtual-machine:/home/txp/testmy/src# ls
main.c  test1.c  test2.c


最终我们还要在testmy目录和src目录下都创建一个CMakeLists.txt:

/*testmy目录下的CMakeLists.txt内容:*/


cmake_minimum_required(VERSION 2.8)

project(main)

add_subdirectory(src)


/*src目下CMakeLists.txt内容:*/

aux_source_directory(. SRC_LIST)

include_directories(../include)

add_executable(main ${SRC_LIST})

set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)


上面第一个CMakeLists.txt里面陌生的语句解释:

add_subdirectory(src)意思是可以向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制的存放位置(subdirectory字母就是子目录的意思,所以意思是:这里指定src目录下存放了源文件,当执行cmake时,就会进入src目录下去找src目录下的CMakeLists.txt,所以在src目录下也建立一个CMakeLists.txt),官方用法是这样的(不过这里暂时没去深究):

add_subdirectory
----------------

Add a subdirectory to the build.

::

  add_subdirectory(source_dir [binary_dir]
                   [EXCLUDE_FROM_ALL])

Add a subdirectory to the build.  The source_dir specifies the
directory in which the source CMakeLists.txt and code files are
located.  If it is a relative path it will be evaluated with respect
to the current directory (the typical usage), but it may also be an
absolute path.  The binary_dir specifies the directory in which to
place the output files.  If it is a relative path it will be evaluated
with respect to the current output directory, but it may also be an
absolute path.  If binary_dir is not specified, the value of
source_dir, before expanding any relative path, will be used (the
typical usage).  The CMakeLists.txt file in the specified source
directory will be processed immediately by CMake before processing in
the current input file continues beyond this command.

If the EXCLUDE_FROM_ALL argument is provided then targets in the
subdirectory will not be included in the ALL target of the parent
directory by default, and will be excluded from IDE project files.
Users must explicitly build targets in the subdirectory.  This is
meant for use when the subdirectory contains a separate part of the
project that is useful but not necessary, such as a set of examples.
Typically the subdirectory should contain its own project() command
invocation so that a full build system will be generated in the
subdirectory (such as a VS IDE solution file).  Note that inter-target
dependencies supercede this exclusion.  If a target built by the
parent project depends on a target in the subdirectory, the dependee
target will be included in the parent project build system to satisfy
the dependency.

第二个CMakeLists.txt内容分析:

aux_source_directory (. SRC_LIST):把当前目录的源文件:main.c test1.c  test2.c都放到变量SRC_LIST里面去。

include_directories (../include):把include目录的头文件包含进来。

set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin):这里面的EXECUTABLE_OUT_PATH和PROJECT_SOURCE_DIR是CMake自带的预定义变量,同时他们的作用分别如下:

 EXECUTABLE_OUTPUT_PATH :目标二进制可执行文件的存放位置

PROJECT_SOURCE_DIR:工程的根目录

所以最终生成的elf文件(也就是我们的最终可执行文件)就会放到bin目录下,然后我们build目录下会成一些配置中间文件。

具体步骤过程我写出来:

root@txp-virtual-machine:/home/txp/testmy# vim CMakeLists.txt
root@txp-virtual-machine:/home/txp/testmy# cd src
root@txp-virtual-machine:/home/txp/testmy/src# ls
main.c  test1.c  test2.c
root@txp-virtual-machine:/home/txp/testmy/src# vim CMakeLists.txt

最后架构如下:

root@txp-virtual-machine:/home/txp/testmy# tree
.
├── bin
├── build
├── CMakeLists.txt
├── include
│   ├── test1.h
│   └── test2.h
└── src
    ├── CMakeLists.txt
    ├── main.c
    ├── test1.c
    └── test2.c

2、编译运行:

root@txp-virtual-machine:/home/txp/testmy# cd build
root@txp-virtual-machine:/home/txp/testmy/build# ls
root@txp-virtual-machine:/home/txp/testmy/build# cmake ..
-- The C compiler identification is GNU 4.8.4
-- The CXX compiler identification is GNU 4.8.4
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/txp/testmy/build
root@txp-virtual-machine:/home/txp/testmy/build# make
Scanning dependencies of target main
[ 33%] Building C object src/CMakeFiles/main.dir/test2.c.o
[ 66%] Building C object src/CMakeFiles/main.dir/test1.c.o
[100%] Building C object src/CMakeFiles/main.dir/main.c.o
Linking C executable ../../bin/main
[100%] Built target main
root@txp-virtual-machine:/home/txp/testmy/build# cd ../bin
root@txp-virtual-machine:/home/txp/testmy/bin# ls
main

注意这里是切换到build目录下去执行cmake哈。 这里为啥这样做呢,我们课可以看到在build目录下执行cmake .. 和make命令后,生成的一些配置文件都会在这个目录下,不会在别的目录下,就这样看起来就舒服整洁多了:

root@txp-virtual-machine:/home/txp/testmy/build# ls
CMakeCache.txt  CMakeFiles  cmake_install.cmake  Makefile  src

现在整个架构如下:

root@txp-virtual-machine:/home/txp/testmy# tree
.
├── bin
│   └── main
├── build
│   ├── CMakeCache.txt
│   ├── CMakeFiles
│   │   ├── 2.8.12.2
│   │   │   ├── CMakeCCompiler.cmake
│   │   │   ├── CMakeCXXCompiler.cmake
│   │   │   ├── CMakeDetermineCompilerABI_C.bin
│   │   │   ├── CMakeDetermineCompilerABI_CXX.bin
│   │   │   ├── CMakeSystem.cmake
│   │   │   ├── CompilerIdC
│   │   │   │   ├── a.out
│   │   │   │   └── CMakeCCompilerId.c
│   │   │   └── CompilerIdCXX
│   │   │       ├── a.out
│   │   │       └── CMakeCXXCompilerId.cpp
│   │   ├── cmake.check_cache
│   │   ├── CMakeDirectoryInformation.cmake
│   │   ├── CMakeOutput.log
│   │   ├── CMakeTmp
│   │   ├── Makefile2
│   │   ├── Makefile.cmake
│   │   ├── progress.marks
│   │   └── TargetDirectories.txt
│   ├── cmake_install.cmake
│   ├── Makefile
│   └── src
│       ├── CMakeFiles
│       │   ├── CMakeDirectoryInformation.cmake
│       │   ├── main.dir
│       │   │   ├── build.make
│       │   │   ├── C.includecache
│       │   │   ├── cmake_clean.cmake
│       │   │   ├── DependInfo.cmake
│       │   │   ├── depend.internal
│       │   │   ├── depend.make
│       │   │   ├── flags.make
│       │   │   ├── link.txt
│       │   │   ├── main.c.o
│       │   │   ├── progress.make
│       │   │   ├── test1.c.o
│       │   │   └── test2.c.o
│       │   └── progress.marks
│       ├── cmake_install.cmake
│       └── Makefile
├── CMakeLists.txt
├── include
│   ├── test1.h
│   └── test2.h
└── src
    ├── CMakeLists.txt
    ├── main.c
    ├── test1.c
    └── test2.c

看一下最终执行结果:

root@txp-virtual-machine:/home/txp/testmy/bin# ./main
i like the cmake
a=8
TXP嵌入式

二、动态库和静态库的学习:

这个话题就回到了我们最开始那位网友提出的需求了;不过我们还是从简单的开始来学习,然后慢慢深入。有的时候我们只需要编译出动态库、静态库,然后给其他程序来调用,那么在cmake里面如何实现呢?具体如下:

注我这用到的源文件内容(test1.c test2.c test1.h test2.h main.c都是一样的来测试

1、为了清晰明了,这里我重新创建了一个目录工程来演示:

root@txp-virtual-machine:/home/txp# mkdir testcmake
root@txp-virtual-machine:/home/txp/testcmake# mkdir build lib lib_test
root@txp-virtual-machine:/home/txp/testcmake# ls
build  lib  lib_test

然后在lib_test目录下放我们的源文件test1.c test1.h,并同时在lib_test目录创建一个CMakeLists.txt;在testcmake目录也创建一个CMakeLists.txt:

root@txp-virtual-machine:/home/txp/testcmake/lib_test# ls
CMakeLists.txt  test1.c  test1.h



/*lib_test目录下的CMakeLists.txt的内容:

aux_source_directory(. SRC_LIST)

add_library(test1_shared SHARED ${SRC_LIST})
add_library(test1_static STATIC ${SRC_LIST})

set_target_properties(test1_shared PROPERTIES OUTPUT_NAME "test1")
set_target_properties(test1_static PROPERTIES OUTPUT_NAME "test1")

set (LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)

解释说明:

add_library: 生成动态库或静态库(第1个参数指定库的名字;第2个参数决定是动态还是静态,如果没有就默认静态;第3个参数指定生成库的源文件)。

set_target_properties: 设置输出的名称,还有其它功能,如设置库的版本号等等。

LIBRARY_OUTPUT_PATH: 库文件的默认输出路径,这里设置为工程目录下的lib目录。

testcmake目录下的CMakeLists.txt内容:

cmake_minimum_required(VERSION 2.8)

project(main)

add_subdirectory(lib_test)

最后架构如下:

root@txp-virtual-machine:/home/txp/testcmake# ls
build  CMakeLists.txt  lib  lib_test
root@txp-virtual-machine:/home/txp/testcmake# tree
.
├── build
├── CMakeLists.txt
├── lib
└── lib_test
    ├── CMakeLists.txt
    ├── test1.c
    └── test1.h

3 directories, 4 files

2、编译结果:

root@txp-virtual-machine:/home/txp/testcmake/build# cmake ..
-- The C compiler identification is GNU 4.8.4
-- The CXX compiler identification is GNU 4.8.4
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/txp/testcmake/build
root@txp-virtual-machine:/home/txp/testcmake/build# make
Scanning dependencies of target test1_shared
[ 50%] Building C object lib_test/CMakeFiles/test1_shared.dir/test1.c.o
Linking C shared library ../../lib/libtest1.so
[ 50%] Built target test1_shared
Scanning dependencies of target test1_static
[100%] Building C object lib_test/CMakeFiles/test1_static.dir/test1.c.o
Linking C static library ../../lib/libtest1.a
[100%] Built target test1_static
root@txp-virtual-machine:/home/txp/testcmake/build# cd ../lib
root@txp-virtual-machine:/home/txp/testcmake/lib# ls
libtest1.a  libtest1.so

注意编译规则上面讲过,这里不再重复

从lib目录下我们可以看到生成了生成了静态库和动态库:libtest1.a  libtest1.so

2、对库进行链接:

现在我们使用刚才生成的库了。把build刚才的配置文件清空,并同时在testcmake目录下创建bin和src目录(跟刚才上面讲的差不多):

root@txp-virtual-machine:/home/txp/testcmake# mkdir src bin
root@txp-virtual-machine:/home/txp/testcmake# ls
bin  build  CMakeLists.txt  lib  lib_test  src
root@txp-virtual-machine:/home/txp/testcmake# cd src
root@txp-virtual-machine:/home/txp/testcmake/src# vim main.c

并在testcmake目录下的CMakeLists.txt内容改成:

cmake_minimum_required(VERSION 2.8)

project(main)

add_subdirectory(lib_test)

add_subdirectory(src)

src目录下要创建一个CMakeLists.txt:

aux_source_directory(.SRC_LIST)

include_directories(../lib_test)

link_directories(${PROJECT_SOURCE_DIR}/lib)

add_executable(main ${SRC_LIST})

target_link_libraries(main test1)

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

解释说明:

--link_directories: 添加非标准的共享库搜索路径。

--target_link_libraries: 把目标文件与库文件进行链接。

3、编译:

root@txp-virtual-machine:/home/txp/testcmake/build# cmake ..
-- The C compiler identification is GNU 4.8.4
-- The CXX compiler identification is GNU 4.8.4
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/txp/testcmake/build
root@txp-virtual-machine:/home/txp/testcmake/build# make
Scanning dependencies of target test1_shared
[ 33%] Building C object lib_test/CMakeFiles/test1_shared.dir/test1.c.o
Linking C shared library ../../lib/libtest1.so
[ 33%] Built target test1_shared
Scanning dependencies of target test1_static
[ 66%] Building C object lib_test/CMakeFiles/test1_static.dir/test1.c.o
Linking C static library ../../lib/libtest1.a
[ 66%] Built target test1_static
Scanning dependencies of target main
[100%] Building C object src/CMakeFiles/main.dir/main.c.o
Linking C executable ../../bin/main
[100%] Built target main
root@txp-virtual-machine:/home/txp/testcmake/build# cd ../bin
root@txp-virtual-machine:/home/txp/testcmake/bin# ls
main
root@txp-virtual-machine:/home/txp/testcmake/bin# ./main
a=6
TXP嵌入式

从上面可以执行成功。同时注意:

我们lib下面又动态库和静态库,而在我们src目录下的CMakeLists.txt里面的target_link_libraries (main test1)默认是使用动态库,如果lib目录下只有静态库,那么这种写法就会去链接静态库。也可以直接指定使用动态库还是静态库,写法是:target_link_libraries (main libtest1.so)或target_link_libraries (main libtest1.a)

同时我们可以查看elf文件到底使用了哪些库文件:

root@txp-virtual-machine:/home/txp/testcmake/bin# readelf -d ./main

Dynamic section at offset 0xe08 contains 26 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libtest1.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000000f (RPATH)              Library rpath: [/home/txp/testcmake/lib]
 0x000000000000000c (INIT)               0x4006a0
 0x000000000000000d (FINI)               0x400894
 0x0000000000000019 (INIT_ARRAY)         0x600df0
 0x000000000000001b (INIT_ARRAYSZ)       8 (bytes)
 0x000000000000001a (FINI_ARRAY)         0x600df8
 0x000000000000001c (FINI_ARRAYSZ)       8 (bytes)
 0x000000006ffffef5 (GNU_HASH)           0x400298
 0x0000000000000005 (STRTAB)             0x4004d8
 0x0000000000000006 (SYMTAB)             0x4002f8
 0x000000000000000a (STRSZ)              260 (bytes)
 0x000000000000000b (SYMENT)             24 (bytes)
 0x0000000000000015 (DEBUG)              0x0
 0x0000000000000003 (PLTGOT)             0x601000
 0x0000000000000002 (PLTRELSZ)           96 (bytes)
 0x0000000000000014 (PLTREL)             RELA
 0x0000000000000017 (JMPREL)             0x400640
 0x0000000000000007 (RELA)               0x400628
 0x0000000000000008 (RELASZ)             24 (bytes)
 0x0000000000000009 (RELAENT)            24 (bytes)
 0x000000006ffffffe (VERNEED)            0x400608
 0x000000006fffffff (VERNEEDNUM)         1
 0x000000006ffffff0 (VERSYM)             0x4005dc
 0x0000000000000000 (NULL)               0x0

三、小结:

这里还有一个网友的提的那个实现,现在我们知道了怎么去使用动态库和静态库就好办了;限于篇幅原因,这个测试留在下篇cmake文章里面来做实验看看到底能不能实现(这里我暂时还没做实验,等我做完实验就会分享出来,这篇文章分享花的时间比较久,大家先暂时消化一下);更多精彩内容,我们下篇见。



声明:本文为OFweek维科号作者发布,不代表OFweek维科号立场。如有侵权或其他问题,请及时联系我们举报。
2
评论

评论

    相关阅读

    暂无数据

    TXP嵌入式

    TXP嵌入式主要分享linux和...

    举报文章问题

    ×
    • 营销广告
    • 重复、旧闻
    • 格式问题
    • 低俗
    • 标题夸张
    • 与事实不符
    • 疑似抄袭
    • 我有话要说
    确定 取消

    举报评论问题

    ×
    • 淫秽色情
    • 营销广告
    • 恶意攻击谩骂
    • 我要吐槽
    确定 取消

    用户登录×

    请输入用户名/手机/邮箱

    请输入密码