高效的Linux系统编程环境

mark

因为笔者的电脑是Windows,所以要进行Linux系统编程不得不准备一台虚拟机,当然子系统Ubuntu也是可以的,因为昨天解决了一个虚拟机固定IP的问题, 《CentOS7虚拟机设置固定IP》 所以一旦连接稳定,那么就可以开始开发了,哈哈,今天主要是通过Clion这个工具(和IDEA是亲兄弟)来进行高效的Linux系统编程环境搭建!

一、准备Linux环境

只要有一台装了Linux的虚拟机就可以,我使用的是CentOS7 Server版,所以,平时使用起来也是直接拿Xshell一连接就可以使用了

二、在Linux下准备开发工具

Cmake 3.x 以上 + gdb 7.8.x 以上 + gcc + gcc-g++

首先卸载预装Cmake 2

1yum remove cmake

安装必要环境

1yum install -y gcc g++ gcc-c++ make automake texinfo wget

安装Cmake

 1wget https://cmake.org/files/v3.14/cmake-3.14.0.tar.gz
 2tar -xf cmake-3.14.0.tar.gz
 3cd cmake-3.14.0
 4./configure
 5make
 6make install
 7
 8# 安装好后的Cmake位于 /usr/local/share/cmake-3.13/,可执行程序位于/usr/local/bin/cmake
 9# 为了让CLion能够自动识别,构建软连接
10ln -s /usr/local/bin/cmake /usr/bin/cmake

如果wget很慢,推荐使用我的

1wget https://img.zouchanglin.cn/cmake-3.14.0.tar.gz

安装gdb

1# 首先安装依赖,termcap
2wget https://ftp.gnu.org/gnu/termcap/termcap-1.3.1.tar.gz
3tar -xf termcap-1.3.1.tar.gz
4cd termcap-1.3.1
5./configure
6make
7make install

如果安装的依赖包下载很慢,推荐用我的

1wget https://img.zouchanglin.cn/termcap-1.3.1.tar.gz

如果依赖包安装完成,开始下一步

 1# 卸载预装gdb
 2yum remove -y gdb
 3
 4# 安装gbd
 5wget http://mirrors.ustc.edu.cn/gnu/gdb/gdb-7.9.tar.xz
 6tar -xf gdb-7.9.tar.xz
 7cd gdb-7.9
 8./configure
 9make
10make install
11
12# gdb将被安装到/usr/local/share/gdb目录,可执行程序位于/usr/local/bin/gdb
13# 为了让CLion能够自动识别,构建软连接。
14ln -s /usr/local/bin/gdb /usr/bin/gdb

如果gdb下载很慢,推荐用我的

1wget https://img.zouchanglin.cn/gdb-7.9.tar.xz

三、CLion配置remote主机

mark

四、愉快的写代码吧

mark

自动同步代码,超人性化提示,唯一的缺点就是对于不懂CMakeList的同学就Over了,下面复习一下CMakeList

五、CMakeList构建项目

cmake 是一个跨平台、开源的构建系统。它是一个集软件构建、测试、打包于一身的软件。它使用与平台和编译器独立的配置文件来对软件编译过程进行控制。 在Windows下也可以使用Cmake进行大型项目的构建,比如我之前编译过OpenCV的源码,就是通过VisualStudio的编译器配合Cmake来完成的!

1. 指定 cmake 的最小版本

1cmake_minimum_required(VERSION 3.4.1)

这行命令是可选的,我们可以不写这句话,但在有些情况下,如果 CMakeLists.txt 文件中使用了一些高版本 cmake 特有的一些命令的时候,就需要加上这样一行,提醒用户升级到该版本之后再执行 cmake。

2. 设置项目名称

1project(demo)

这个命令不是强制性的,但最好都加上。它会引入两个变量 demo_BINARY_DIR 和 demo_SOURCE_DIR,同时,cmake 自动定义了两个等价的变量 PROJECT_BINARY_DIR 和 PROJECT_SOURCE_DIR。

3. 设置编译类型

1add_executable(demo demo.cpp) # 生成可执行文件
2add_library(common STATIC util.cpp) # 生成静态库
3add_library(common SHARED util.cpp) # 生成动态库或共享库

add_library 默认生成是静态库,通过以上命令生成文件名字,

  • 在 Linux 下是: demo libcommon.a libcommon.so
  • 在 Windows 下是: demo.exe common.lib common.dll

4. 指定编译包含的源文件

4.1 明确指定包含哪些源文件

1add_library(demo demo.cpp test.cpp util.cpp)

4.2 搜索所有的 cpp 文件

aux_source_directory(dir VAR) 发现一个目录下所有的源代码文件并将列表存储在一个变量中。

1aux_source_directory(. SRC_LIST) # 搜索当前目录下的所有.cpp文件
2add_library(demo ${SRC_LIST})

自定义搜索规则

 1file(GLOB SRC_LIST "*.cpp" "protocol/*.cpp")
 2add_library(demo ${SRC_LIST})
 3# 或者
 4file(GLOB SRC_LIST "*.cpp")
 5file(GLOB SRC_PROTOCOL_LIST "protocol/*.cpp")
 6add_library(demo ${SRC_LIST} ${SRC_PROTOCOL_LIST})
 7# 或者
 8aux_source_directory(. SRC_LIST)
 9aux_source_directory(protocol SRC_PROTOCOL_LIST)
10add_library(demo ${SRC_LIST} ${SRC_PROTOCOL_LIST})

5. 查找指定的库文件

find_library(VAR name path)查找到指定的预编译库,并将它的路径存储在变量中。 默认的搜索路径为 cmake 包含的系统库,因此如果是 NDK 的公共库只需要指定库的 name 即可

1find_library( # Sets the name of the path variable.
2              log-lib
3 
4              # Specifies the name of the NDK library that
5              # you want CMake to locate.
6              log )

6. 设置包含的目录

1include_directories(
2    ${CMAKE_CURRENT_SOURCE_DIR}
3    ${CMAKE_CURRENT_BINARY_DIR}
4    ${CMAKE_CURRENT_SOURCE_DIR}/include
5)

Linux 下还可以通过如下方式设置包含的目录

1set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I${CMAKE_CURRENT_SOURCE_DIR}")

7. 设置链接库搜索目录

1link_directories(
2    ${CMAKE_CURRENT_SOURCE_DIR}/libs
3)

Linux 下还可以通过如下方式设置包含的目录

1set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_CURRENT_SOURCE_DIR}/libs")

8. 设置 target 需要链接的库

1target_link_libraries( # 目标库
2                       demo
3 
4                       # 目标库需要链接的库
5                       # log-lib 是上面 find_library 指定的变量名
6                       ${log-lib} )

在 Windows 下,系统会根据链接库目录,搜索xxx.lib 文件,Linux 下会搜索 xxx.so 或者 xxx.a 文件,如果都存在会优先链接动态库(so 后缀)

8.1 指定链接动态库或静态库

1target_link_libraries(demo libface.a) # 链接libface.a
2target_link_libraries(demo libface.so) # 链接libface.so

8.2 指定全路径

1target_link_libraries(demo ${CMAKE_CURRENT_SOURCE_DIR}/libs/libface.a)
2target_link_libraries(demo ${CMAKE_CURRENT_SOURCE_DIR}/libs/libface.so)

8.3 指定链接多个库

1target_link_libraries(demo
2    ${CMAKE_CURRENT_SOURCE_DIR}/libs/libface.a
3    boost_system.a
4    boost_thread
5    pthread)

9. 设置变量

9.1 set 直接设置变量的值

1set(SRC_LIST main.cpp test.cpp)
2add_executable(demo ${SRC_LIST})

9.2 set 追加设置变量的值

1set(SRC_LIST main.cpp)
2set(SRC_LIST ${SRC_LIST} test.cpp)
3add_executable(demo ${SRC_LIST})

9.3 list 追加或者删除变量的值

1set(SRC_LIST main.cpp)
2list(APPEND SRC_LIST test.cpp)
3list(REMOVE_ITEM SRC_LIST main.cpp)
4add_executable(demo ${SRC_LIST})

六、CMake项目示例

1、简单项目

新建文件 main.c,内容如下,新建文件 CMakeLists.txt(命名必须是 CMakeLists.txt,注意大小写)

mark

一般我们采用 cmake 的 out-of-source 方式来构建(即生成的中间产物和源代码分离),这样做可以让生成的文件和源文件不会弄混,且目录结构看起来也会清晰明了。所以推荐使用这种方式,至于这个文件夹的命名并无限制,我们习惯命名为 build。

我们进入build文件夹,执行cmake.... 表示上一级目录,cmake 会在上一级目录下找到 CMakeLists.txt 文件并编译,并生成如下图所示的一些中间文件

mark

直接执行 make命令,生成可执行程序,如下图:

mark

2、复杂项目

mark

CMakeList.txt

1cmake_minimum_required (VERSION 2.8)
2project(demo)
3aux_source_directory(. DIR_SRCS)
4# 添加math子目录
5add_subdirectory(math)
6# 指定生成目标
7add_executable(demo ${DIR_SRCS})
8# 添加链接库
9target_link_libraries(demo MathFunctions)

main.c

1#include <stdio.h>
2#include "math/MathFunctions.h"
3
4int main() {
5    printf("Hello World!\n");
6    printf("Add(1,2) ret = %d\n", add(1,2));
7    return 0;
8}

math里的CMakeList.txt

1aux_source_directory(. DIR_LIB_SRCS)
2# 生成链接库
3add_library(MathFunctions ${DIR_LIB_SRCS})

math里的MathFunctions.h 和MathFunctions.c

1#ifndef define _MATHFUNCTIONS_H__
2#define _MATHFUNCTIONS_H__
3
4int add(int num, int num2);
5
6#endif //!define _MATHFUNCTIONS_H__
1#include <stdio.h>
2#include "MathFunctions.h"
3
4int add(int num, int num2){
5	return num + num2;
6}

同样的也只需要进入build目录,进行cmake ..

mark