C++编译之make cmake bazel模板

2023-05-16

​前面文章介绍了C++编译过程:预处理、编译、汇编、链接,内容比较简单,只要会使用命令行,就能根据文章的内容实践操作,直观的了解编译全过程。

一个项目往往不只一两个cpp文件,此时命令行编译的方式就会显得捉襟见肘。然而在实际项目中,有序构建并不需要开发人员投入太多精力,这就必须要用到编译脚本,了解一两个常用命令,就可以搞定这个复杂的过程。

如果要说什么是C++开发中可以真正做到一劳永逸的事情,那就是编译脚本。编译脚本是一个规则描述文件,配合工具就可以完成编译,其维护成本极低,只需要参考模板简单改改,就可以拿来直接用,岂不美哉。

make与Makefile

make是上个世纪70年代诞生的工具,能够沿用至今,必属经典。

大型工程的编译面临依赖多、耗时长的问题,有时候你只改了一小段代码,却要等好几十秒甚至几分钟来等待编译结果。在企业级的中心化构建系统中,还可能会存在队列等待的问题。

其实大型工程也是基于一些基础的小工程构建的,将大型工程用可插拔的理念,拆分成一个个小单元,那么在这些小的单元中,其实用不到太复杂的构建系统,选择make可以快速验证demo程序是否符合预期。没有RPC、网络、权限校验、流程等诸多工程问题。

make指令需要一个构建规则,这个规则默认放在Makefile中,当然也可以通过-f参数指定规则文件。话不多说,直接上菜:

$(shell if [ ! -d sbin ]; then mkdir sbin; fi;)
TAR := ./sbin/cppcompiletemplate
CXX := g++ # -m32

SOURCES :=$(wildcard *.cpp) $(wildcard *.c) $(wildcard *.hpp) $(wildcard *.cc)
AllDirs := $(shell ls -R | grep '^\./.*:$$' | awk '{gsub(":","");print}' | grep -vE 'cmakebuild|sbin')
$(info AllDirs: $(AllDirs))
SOURCES += $(foreach subdir,$(AllDirs),$(wildcard $(subdir)/*.cpp) $(wildcard $(subdir)/*.c)) # 遍历子目录

COPTION := -W -Wall -Wfatal-errors -fpermissive # -Werror -Wshadow -Wdouble-promotion -fno-common -Wconversion
#COPTION += -Wno-unused-function -Wno-error=missing-field-initializers

CFLAGS := -pthread -std=c++11 $(COPTION)
CFLAGS_DEBUG := -g -O0
CFLAGS_RELEASE := -s -O2 -static-libstdc++ -static-libgcc # -static

###############################################################################################################
DEFS := #-DNDEBUG
CFLAGS += # -pg
INC := # -I ./3rdlib/jsoncpp/include
LIB := # ./3rdlib/jsoncpp/lib/libjsoncpp.a
LFLAGS := -pthread #-lrt -ldl
###############################################################################################################

all: $(TAR)
debug: $(TAR)

$(TAR): $(SOURCES)
	@echo -e =====================DEBUG=========================
	$(CXX) $(DEFS) $(CFLAGS) $(CFLAGS_DEBUG) -o $(TAR) $(SOURCES) $(INC) $(LIB) $(LFLAGS)

release: $(SOURCES)
	@echo -e =====================RELEASE=======================
	$(CXX) $(DEFS) $(CFLAGS) $(CFLAGS_RELEASE) -o $(TAR) $(SOURCES) $(INC) $(LIB) $(LFLAGS)

%.o: %.cpp
	@echo -e ======================COMPLING====================
	@echo Compling $< "->" $@
	@echo -e ==================================================
	$(CXX) $(CFLAGS) -c $*.cpp $(INC)

clean: 
	rm -f *.o
	rm -f $(TAR)

Makefile是通过变量的方式来组织编译规则。这没什么难的,熟悉命令行的基本就能看懂。使用方法:

  1. 拷贝文件内容到工程根目录Makefile文件中
  2. 执行make指令,会扫描当前目录与子目录下的所有c++源文件进行编译

通常,使用时只需要修改#注释包裹的内容。这是我使用得最多的模板,可适用于绝大部分单体服务工程。

注意:这里我注释掉了-static链接选项,实际工程中一般不要使用-static静态链接,详细原因我在《Linux C++生成静态库与动态库》中有说明。

cmake与CMakeLists.txt

make虽然简单方便,但是可移植性不足。比如上面的Makefile第一行命令(生成sbin目录)和最后一行命令(清除可执行文件),在windows下是行不通的,cmake就可以完美解决这个问题。

cmake诞生于2000年,比make晚了23年。cmake本身不直接产生可执行文件,而是用来生成标准的Makefile规则描述文件或开发工程。

如果你去看github上的开源库,可以发现绝大部分库都使用cmake做为编译工具,其原因一是可以跨平台,二是cmake有生态的理念,内置了很多宏,可以快速引入其他依赖包,如果你编译过grpc就可以深刻体会到这点。继续上菜:

cmake_minimum_required(VERSION 2.8) # 指定cmake的最小版本
cmake_policy(SET CMP0015 NEW) # 解决Policy CMP0015 is not set错误

set(DEMO_NAME cppcompiletemplate)
set(PROJECT_SOURCE_DIR ".")
set(EXECUTABLE_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/sbin") # 指定可执行程序编译输出目录
set(LIBRARY_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/lib") # 指定静态库或者动态库编译输出目录

set(CMAKE_CXX_COMPILER "g++")
set(CMAKE_C_COMPILER ${CMAKE_CXX_COMPILER})  # 使用g++来编译.c文件,否则c的函数就需要extern "C"导出

# 自动检测编译器是否支持C++11
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(COMPILER_SUPPORTS_CXX0X)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
    message(WARNING "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()

# add_compile_options命令添加的编译选项是针对所有编译器的(包括c和c++编译器)
add_compile_options(-W -Wall -Wfatal-errors -fpermissive)  # add_compile_options在末尾添加参数,不能加双引号

set(LFLAGS_DEBUG "-O0 -g")  # Debug模式 
set(LFLAGS_RELEASE "-O2 -s -static-libstdc++ -static-libgcc")  # Release模式

# set命令设置CMAKE_C_FLAGS或CMAKE_CXX_FLAGS变量则是分别只针对c和c++编译器的
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${LFLAGS_DEBUG}") # 使用 cmake -DCMAKE_BUILD_TYPE=Debug ../
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${LFLAGS_DEBUG}")

set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${LFLAGS_RELEASE}") # 使用 cmake -DCMAKE_BUILD_TYPE=Release ../
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${LFLAGS_RELEASE}")


###############################################################################################################
add_definitions() # 额外的宏定义
add_compile_options() # 额外的编译选项
set(SRC_DIR_ROOT ) # 设置源文件目录,这里不能用双引号
include_directories() # 设置包含目录
link_directories() # 设置动态和静态链接库搜索目录
link_libraries() # 静态链接link_libraries用在add_executable之前,需要结合link_directories使用
###############################################################################################################


include_directories(./ ${SRC_DIR_ROOT})
FOREACH(SRC_DIR ${SRC_DIR_ROOT})
    file(GLOB_RECURSE USER_FILE_PATH ${USER_FILE_PATH} ${SRC_DIR}/*.cc ${SRC_DIR}/*.cpp ${SRC_DIR}/*.hpp)
ENDFOREACH(SRC_DIR)

aux_source_directory(. SRC_LIST) # 编译源文件
add_executable(${DEMO_NAME} ${SRC_LIST} ${USER_FILE_PATH}) # 编译可执行程序

#target_link_libraries(${DEMO_NAME} rt) # 动态链接target_link_libraries用在add_executable之后,需要结合link_directories使用


# -pthread既是编译指令,也是链接指令。编译只能指定-pthread,也可以不指定。
# 链接时:-pthread参数最终是-pthread指令,pthread是参数会转换成-lpthread,和直接指定-lpthread一样的效果。
# set_target_properties一次性强制指定编译和链接-pthread,需要放到add_executable之后
set_target_properties(${DEMO_NAME} PROPERTIES COMPILE_FLAGS "-pthread" LINK_FLAGS "-pthread")

message(STATUS "${SRC_LIST} ${USER_FILE_PATH}")
#add_library(${DEMO_NAME} STATIC ${SRC_LIST}) # 编译静态库
#add_library(${DEMO_NAME} SHARED ${SRC_LIST}) # 编译动态库

make使用变量组织编译规则,cmake在make的基础上增加了函数的概念。但是cmake的使用文档晦涩难懂,所以大部分内容我都写了注释。使用方法:

  1. 拷贝文件内容到工程根目录CMakeLists.txt中
  2. 创建cmakebuild子目录,并进入cmakebuild目录
  • 生成Debug模式Makefile:cmake -DCMAKE_BUILD_TYPE=Debug ..
  • 生成Release模式Makefile:cmake -DCMAKE_BUILD_TYPE=Release ..

大部分情况下,使用时可以像使用Makefile那样,只需要修改#注释包裹的内容。如果需要引入第三方库,参考如下:

include_directories(./3rdlib/jsoncpp/include) # 设置包含目录
link_directories(./3rdlib/jsoncpp/lib) # 设置动态和静态链接库搜索目录
link_libraries(libjsoncpp.a)

CMakeLists.txt主要通过函数的方式来组织编译规则,需要提醒的是在一些大型工程中,比如folly和mysql,它们的CMakeLists.txt会使用正则表达式MATCHES来匹配文件路径,而"+"号在正则表达式中具有特殊含义,因此这些工程不能放在类似于/C++/这样的路径下。在modern cmake(3.x版本)中还引入对象的概念,然而对象方式组织编译最好最清晰的当属分布式编译工具bazel。

bazel与BUILD

bazel是google推出的构建工具,其社区非常活跃,推荐使用bazelisk安装bazel工具。其编译规则描述文件是BUILD,编写方式和python语法类似。

cc_import(
    name = 'libjsoncpp',
    hdrs = glob([
        '3rdlib/jsoncpp/include/**/*.h',
        ]),
    static_library = '3rdlib/jsoncpp/lib/libjsoncpp.a',
)

cc_library(
    name = 'cppcompiletemplate_comm',
    srcs = glob([
        '*.cpp',
        '*.cc',
        '*.hpp',
    ],
    exclude = ['main.cpp'],
    ),
    hdrs = glob(['*.h']),
    includes =['.'],
    deps = [
        #':libjsoncpp',
    ],
    copts = [
        '-W',
        '-Wall',
        '-Werror',
        '--std=c++11',
    ],
    linkopts = [
        '-pthread',
    ]
)

cc_binary(
    name = 'cppcompiletemplate',
    srcs = ['main.cpp'],
    includes =['.'],
    deps = [
        ':cppcompiletemplate_comm',
    ],
    copts = [
        '-W',
        '-Wall',
        '-Werror',
        '--std=c++11',
    ],
    linkopts = []
)

是不是很简单,

  • cc_import()导入第三方库(如果需要)
  • cc_library()将除main.cpp以外的文件封装成静态库对象,可以再拆分成多个cc_library对象,方便其他工程依赖
  • cc_binary()编译成最终的可执行文件

使用方法:

  1. 拷贝文件到工程根目录
  2. 在仓库的根目录下创建一个WORKSPACE文件
  3. 执行bazel build :cppcompiletemplate生成二进制,同理,执行bazel build :cppcompiletemplate_comm则生成lib库。

生成的文件在WORKSPACE文件所在目录下的bazel-out软链接的目录中。

bazel按对象来组织编译规则的理念,让依赖看起来非常清晰,而且其缓存机制,使得在大型工程中仍然有较快的构建速度,嘎嘎好。

总结

  • make的Makefile使用变量来描述编译规则,经典范式,简单易懂,适合小demo;
  • cmake的CMakeLists.txt通过变量、函数来描述编译规则,跨平台,生态好,使用广泛;
  • bazel的BUILD使用对象来描述编译规则,依赖清晰,新生代社区活跃,适合大型工程;

最后,上述三个编译模板我都放到github了,按需自取:https://github.com/jegbrother/CPPCompileTemplatehttps://github.com/jegbrother/CPPCompileTemplate

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++编译之make cmake bazel模板 的相关文章

  • STM32 BOOT引起硬件死机

    STM32的三种启动方式依靠BOOT0和BOOT1两个引脚的电平来决定 xff0c ST官方推荐的是串联10k电阻然后在接高电平或接地 我用0R直接接地的 xff0c 没有串联10k电阻 xff0c 造成STM32的硬件死机 在实际的应用中
  • 远程 sshd提示:Server unexpectedly closed network connection

    root 64 xx vim etc ssh sshd config 修改端口为3330 root 64 xx iptables I INPUT p tcp dport 3330 j ACCEPT 添加防火墙3330端口 允许 root 6
  • linux驱动开发流程和方法

    方法一 xff1a 将驱动编入内核的方法 手把手教你写第一个Linux驱动程序 https blog csdn net morixinguan article details 54620088 方法二 xff1a 简单实例讲解linux的m
  • Ubuntu 出现apt-get: Package has no installation candidate问题解决办法

    apt get install tftpd tftp openbsd inetd 提示apt get Package has no installation candidate 解决方法如下 xff1a 先检查虚拟机网络是否NAT模式 xf
  • Vim/gVim 中文显示为乱码的解决办法

    打开vimrc文件 xff0c 在vim的安装目录下可以找到该文件 xff0c 或在windows下是在vim gvim下输入 edit vim vimrc 在文件的末尾添加一句 set fileencodings 61 utf 8 gbk
  • 关于字,半字,字节之间的关系

    一直搞不清楚字 xff0c 半字 xff0c 字节之间的关系 xff0c 查了一下资料 xff0c 明白了 字 xff0c 半字 xff0c 字节 大小是根据不同的操作系统来说的 xff0c 32位系统 字 gt 32bit 半字 gt 1
  • android json解析及简单例子

    JSON的定义 xff1a 一种轻量级的数据交换格式 xff0c 具有良好的可读和便于快速编写的特性 业内主流技术为其提供了完整的解决方案 xff08 有点类似于正则表达式 xff0c 获得了当今大部分语言的支持 xff09 xff0c 从
  • vim-plug的使用方法

    vim plug介绍 Vim plug 是一个自由 开源 速度非常快的 并行地安装或更新插件 xff0c 极简的 vim 插件管理器 GIT获取和安装 https git scm com 插件获取 https github com june
  • .NetCore swagger发布到iis时访问api出现404的解决方案

    介绍 使用netcore作为纯后端提供api已经变得越来越频繁 xff0c swagger也成为很多人的选择 通常会在代码中限制ASPNETCORE ENVIRONMENT为Production时关闭swagger 但是往往我们需要将api
  • 新手树莓派4B安装Supervised+Home Assistant及问题解决

    测试平台 xff1a 树莓派4B 4G 系统版本 xff1a Raspberry Pi OS with desktop and recommended software Release date September 22nd 2022 Sy
  • 无人机高精度定位之——RTK与PPK概念扫盲

    无人机高精度定位之 RTK与PPK概念扫盲 无人机的兴起 xff0c 已经让很多行业激动不已 xff0c 如电力巡检 应急救援 测绘 农业植保等行业 而随着高精度卫星导航技术的加持 xff0c 让无人机定位更加高效 安全 灵活 xff0c
  • 数据结构与算法--01数组:为什么大多编程语言中数组从0开始编号?

    数据结构与算法 01数组 xff1a 为什么很多编程语言中数组从0开始编号 xff1f 一 数组特性二 数组访问越界问题三 数组与容器四 回到开篇五 总结 一 数组特性 1 数组本质上是一种线性表数据结构 xff0c 用一组连续的内存空间来
  • 数据结构与算法--02链表-如何轻松写出链表代码

    数据结构与算法 02链表 如何轻松写出链表代码 写好链表并不是件容易的事情 xff0c 尤其是一些复杂的链表操作 xff0c 如链表反转 有序链表合并等等 即使能够写出代码 xff0c 但及其容易出错 所以付出一定量的精力是前提条件 xff
  • QT for Windows安装配置总结及采坑问题汇总

    QT for Windows安装配置总结及采坑问题汇总 一 安装包下载二 安装三 Qt Creator配置四 遇到的问题 一 安装包下载 1 Qt官方下载地址 xff1a http download qt io archive qt xff
  • IOS系统历届版本大回顾(<iOS7)

    APPLE xff0c 一种常见的水果 xff0c 但在人类的进化史上扮演了2次拯救世界的角色 第一次是在1666年一个夏末的傍晚 xff0c 在英格兰林肯郡的乌尔斯索普 xff0c 当一个年轻人坐在树下 xff0c 埋头读书的时候 xff
  • 总结-虚拟机安装OS X系统步骤及遇到的问题

    一 安装步骤 1 创建一个文件夹 xff0c 用于向虚拟机系统共享文件 xff0c 如 xff1a work 2 下载好所需的安装包 xff1a a VMware虚拟机安装包 xff08 包含unlocker软件 xff0c 用于解锁VMw
  • Git-回退到指定版本

    Git 回退到指定版本 1 方法一 xff1a git reset2 方法二 xff1a git commit amend 1 方法一 xff1a git reset 直接回退到指定版本 xff0c 目标版本之后的提交将被删除 情况一 xf
  • 我的2011--快乐最重要

    呵呵 xff0c 听着郭德纲和于谦老师的相声 xff0c 开始写这篇文章 xff0c 刚毕业不到六个月 xff0c 就换了一份工作 xff0c 很多事情都在意料之外 xff0c 很多事情又在意料之中 xff0c 总之 xff0c 以后回忆到
  • 如何在github的wiki中添加新的图片

    本文简单介绍在github的wiki中添加新的图片对方法 在github的wiki中 xff0c 可以展现图片 xff0c 可是 xff0c 怎么添加图片 xff0c 从网页上展示的信息来看 xff0c 不是很清楚 添加图片 xff0c 基
  • iOS-AppStore上传应用更新之——Xcode上传ipa

    iOS AppStore上传应用更新之 Xcode上传ipa 一 App Store Connect添加新版本配置二 Xcode验证IPA有效性三 生成IPA包 xff0c 通过xcode直接上传至AppStore四 注意事项 好久没有打包

随机推荐

  • CSDN博客搬家至掘金

    博客搬家说明 xff1a 作为一名程序员 xff0c 掘金是目前最适合我们的一个平台 xff0c 所以决定将CSDN博客搬迁至掘金 xff01 CSDN是我第一个接触的博客平台 xff0c 你将成为我最美的回忆 xff0c 永远爱你 xff
  • 机器人学习之项目- Project1 : Go Chase it!(一)

    1 项目简介 任务概述 在这个项目中 xff0c 在catkin ws src中创建两个ROS包 drive bot和ball chaser 下面是设计机器人的步骤 xff0c 把它安置在一个设定的世界里 xff0c 并编程让它追逐白色的球
  • R6002-floating point not loaded 的问题解决方法

    最近项目的要计算浮点数据 xff0c 为了调试方便 xff0c 输出计算结果值到DEBUG信息 xff0c 结果却出现 R6002 错误 Google了一下 xff0c MSDN上对于R6002的描述信息是 xff1a 错误消息 未加载浮点
  • Eclipse 创建spring Boot 项目pom.xml报错处理

    1 最首先检查版本问题 xff0c 需要的话更新maven插件 点击help Install New Software Work with输入如下地址 https otto takari io content sites m2e extra
  • python如何查看函数或者模块的源代码

    查看函数的源代码 xff1a 一般来说 xff0c 一个python函数会自带一个 code 变量 xff0c 其中包含了该函数源码的文件路径 以 os path exists 函数为例 xff0c 打印它的源代码文件位置 xff1a im
  • SUN RGB-D数据集的理解

    SUN RGB D数据集是普灵斯顿大学的 Vision amp Robotics Group 公开的一个有关场景理解的数据集 官方介绍在此 xff0c 其中有视频介绍 视频介绍已经很详细了 xff0c 建议先看懂视频 此博客仅仅列出个人认为
  • ORB_SLAM2--源码编译

    前言 学习ORB SLAM2 xff0c 从编译源码开始 ORB SLAM2的github地址 https github com raulmur ORB SLAM2 一 准备工作 1 安装依赖库 sudo apt install cmake
  • ORB_SLAM2的单目SLAM提高关键帧的个数

    一 前言 最近在结合ORB SLAM2和Map2DFusion xff0c 来做无人机航拍视频建图 xff0c 基本完成了pipeline xff0c 但发现出来的效果没有Map2DFusion官方的效果好 xff08 第一张图是我自己处理
  • fmt报错

    在编译Map2DFusion时 xff0c 遇到fmt报错的问题 xff1a home user01 ZhengJiafang Map2DFusion src Map2D cpp 23 usr local include sophus co
  • android4.0新控件Switch方法解析

    就是很像开关的那种控件 xff0c 它只有两个状态 xff1a on和off xff1a 在IOS中 xff0c 有个UISwitch控件 xff0c 其效果图 xff0c 如下 xff1a 在android4 0里面 xff0c 添加了一
  • 视觉SLAM融合GPS尝试

    一 前言 最近在做无人机建图的相关工作 xff0c 基本的方案是ORB SLAM2 43 Map2DFusion 在调试好代码后 xff0c 我利用大疆精灵4在附近的一个公园进行算法测试 xff0c 得到的效果图如下 xff1a 但在一些细
  • python读取与保存图片的exif信息

    图片的exif文件格式中保存了很多信息 xff0c 比如GPS经纬度 xff0c 高度 xff0c 焦距等信息 在图片的属性中可以看到这些信息 xff1a 我们可以使用python来进行exif数据的读取和保存 1 首先安装piexif p
  • ROS深度图转化为点云

    自己编写C 43 43 的ROS代码 xff0c 订阅D435i深度图像 xff0c 转化为点云数据 xff0c 并发布出去 说明 xff1a D435i本身就可以输出点云 xff0c 不需要自己编写代码 本博客的目的是通过自己编写深度图转
  • 大疆校招测评题--循环赛问题

    笔者在2022 7参加了大疆的测评题 其中有道循环赛问题 xff0c 记录下解题思路 循环赛问题 六名选手A B C D E F进行循环赛 每两名选手间比赛一次 xff0c 每名选手每天比赛一场 五天内完成循环赛 已知 xff1a 第一天C
  • Ubuntu22.04安装libudev-dev时的Bug

    新安装了Ubuntu22 04 xff0c 然后安装libudev dev xff1a sudo apt install libudev dev 发现了非常奇怪的事情 xff1a 正在读取软件包列表 完成 正在分析软件包的依赖关系树 完成
  • python爬虫教程——科研向

    引言 在科研中 xff0c 有时需要爬取网站上的文本数据 xff0c 用于统计分析 xff0c 或是制作机器学习所用的数据集 举个例子 xff0c 假如我们需要在世界野生鸟类声音网XenoCanto中 xff0c 爬取网站上的鸟类声音标签信
  • Ubuntu18.04虚拟机下安装opencv

    内容提要 xff1a 此文主要讲在Ubuntu18 04虚拟机下通过编译源码的方式安装opencv 一 首先 xff0c 安装VMware Workstations vmware下载渠道很多我是通过360软件管家下载的 安装过程默认就好 x
  • 笔记本Ubuntu18.04安装NVIDIA驱动,配置darknet环境,并跑yolov3例程(完全过程记录)

    前言 xff1a 我的笔记本电脑显卡为GTX 1050 xff0c 想利用它跑深度学习 xff0c 但是配置环境时遇到了好多问题 前前后后重装了十几次ubuntu xff0c 一个一个试网上的问题解决方案 xff0c 最终把环境搭好了 说多
  • Win7安装Ubuntu1804双系统

    靖哥哥我平时使用ubuntu不多 xff0c 所以都是在虚拟机安装ubuntn 不过因为有一次物理机强制关机 xff0c 导致虚拟机文件损坏 xff0c 此后再使用虚拟机时 xff0c 常遇到死机的情况 xff0c 所以琢磨一下安装双系统
  • C++编译之make cmake bazel模板

    前面文章介绍了C 43 43 编译过程 xff1a 预处理 编译 汇编 链接 xff0c 内容比较简单 xff0c 只要会使用命令行 xff0c 就能根据文章的内容实践操作 xff0c 直观的了解编译全过程 一个项目往往不只一两个cpp文件