c++的编译安装一直是阻碍C++发展的痛点,于是对于它的使用,一直在改进的路上。
它需要解决的问题无非是,编译依赖,运行依赖。编译依赖就包括了依赖的库,依赖的头文件,运行依赖主要是依赖的库。然后问题回归成版本不兼容的各种问题,平台运行不兼容的各种问题。编译的问题,编译的速度都影响它平台性的扩展。而它的编译配置文件的编写也有很多学习成本。本文就是针对编译来介绍几个常用的工具。
g++
g++是GNU开发的C++编译器,是GCC(GNU Compiler Collection)GNU编译器套件的组成部分。另外,gcc是GNU的C编译器。官方手册上的参数此时可以忽略。。。学习成本非常高。
g++ 是根据汇编的改进。 .cpp. (-E预处理)->. .i -> (编译 -S) --> .s -> (汇编 -c) -> .o -->(链接)--> bin
1)静态链接库使用绝对路径,动态链接库使用-l。以boost库为例,如果我们要使用静态库则可书写如下:
g++ main.cpp -pthread /usr/lib64/libboost_thread.a /usr/lib64/libboost_system.a
(2)使用-Wl,-Bstatic
告诉链接器ld
链接静态库,不存在静态库,则ld
报错,只存在动态链接库也报错。使用-Wl,-Bdynamic
告诉链接器优先使用动态链接库,如果只存在静态库,则链接静态库,不报错。示例如下:
g++ main.cpp -Wl,-Bstatic -lboost_system -lboost_thread -Wl,-Bdynamic
GCC VS G++
gcc和g++的主要区别
1. 对于 *.c和*.cpp文件,gcc分别当做c和cpp文件编译(c和cpp的语法强度是不一样的)
2. 对于 *.c和*.cpp文件,g++则统一当做cpp文件编译
3. 使用g++编译文件时,g++会自动链接标准库STL,而gcc不会自动链接STL
4. gcc在编译C文件时,可使用的预定义宏是比较少的
5. gcc在编译cpp文件时/g++在编译c文件和cpp文件时(这时候gcc和g++调用的都是cpp文件的编译器),会加入一些额外的宏。
6.在用gcc编译c++文件时,为了能够使用STL,需要加参数 –lstdc++ ,但这并不代表 gcc –lstdc++ 和 g++等价,它们的区别不仅仅是这个。
make
Makefile
f对于一个文件,用gcc/g++的编写也非常复杂,对于一个工程的make,已经不是一个脚本可以解决和覆盖的。于是有make 工具。用Makefile文件定义编译逻辑,用make工具进行编译。
GNU的make工作时的执行步骤如下:(想来其它的make也是类似)
- 读入所有的Makefile。
- 读入被include的其它Makefile。
- 初始化文件中的变量。
- 推导隐晦规则,并分析所有规则。
- 为所有的目标文件创建依赖关系链。
- 根据依赖关系,决定哪些目标要重新生成。
- 执行生成命令。
cmake
有了make以后工程的编译变得简单,但是Makefile还是对于平台是不兼容的,同一个工程在不同平台下,Makefile文件有不同的配置。同一份代码,不同的平台,会编不过。于是有了CMake
CMake全称为“cross platform make”,是一个开源的跨平台自动化构建系统。使用指定名为CMakeLists.txt
的配置文件可以控制软件的构建、测试和打包等流程。同时,通过编写平台无关的CMakeLists.txt
文件和需要简单的配置,CMake就能生成对应目标平台的构建文件,例如:类Unix系统的makefile文件、Windows的Visual Studio工程或者Mac的Xcode工程,大大简化了跨平台和交叉编译方面的工作。
cmake 是在make之前根据CMakeLists的定义生产makefile,解决不同Makefile跨平台配置的问题。让C++的工程有了跨平台的兼容性。
Bazel
Google家出的Bazel 也是跨平台的工程编译工具。更强大的优势在于,它可以支持多种开发语言的项目。
于是向tensorflow这种需要跨语言,跨平台,多文件的复杂工程,用bazel编译管理就再合适不过了。一份代码可以编译出同一版本的多语言,多平台支持的可执行文件。
命令非常简单 bazel build xxx 依赖关系定义在 BUILD文件中。
定义库
cc_library(
name = "hello-greet",
srcs = ["hello-greet.cc"],
hdrs = ["hello-greet.h"],
visibility = ["//main:__pkg__"],
)
cc_library(
name = "sandwich",
srcs = ["sandwich.cc"],
hdrs = ["sandwich.h"],
deps = [":bread"],
)
cc_library(
name = "bread",
srcs = ["bread.cc"],
hdrs = ["bread.h"],
deps = [":flour"],
)
cc_library(
name = "flour",
srcs = ["flour.cc"],
hdrs = ["flour.h"],
)
定义target
cc_binary(
name = "hello-world",
srcs = ["hello-world.cc"],
deps = [
":hello-time",
"//lib:hello-greet",
],
)
外部库可以用http
new_http_archive(
name = "gtest",
url = "https://googletest.googlecode.com/files/gtest-1.7.0.zip",
sha256 = "247ca18dd83f53deb1328be17e4b1be31514cedfc1e3424f672bf11fd7e0d60d",
build_file = "gtest.BUILD",
strip_prefix = "gtest-1.7.0",
)
cc_library(
name = "main",
srcs = glob(
["src/*.cc"],
exclude = ["src/gtest-all.cc"]
),
hdrs = glob([
"include/**/*.h",
"src/*.h"
]),
copts = ["-Iexternal/gtest/include"],
linkopts = ["-pthread"],
visibility = ["//visibility:public"],
)
bazel build main:hello-world
最后C++包的安装
linux(Centos) yum install rpm -ivh
ubuntu : apt-get
macos brew install