C++服务开发环境-万事开头难

对于开发人员来说,仅仅学习编程语言的语法是不够的,还需要学习这门编程语言对应的构建流程,不然写出来的代码怎么变成程序运行起来呢?

出生较晚的编程语言,如golang、python等,都有对开发者友好的构建工具链,golang开发者仅仅需要花少量时间就能学会go mod和go build,很方便的将源码打包成程序拿去运行。

而出身于40多年前的C/C++语言,构建工具的学习成本并不低,而且一直在更新换代。

今天主要介绍一套适合C++服务端开发者在自己个人电脑上愉快开发和测试的方法。如果你需要创建一个伟大的C++服务端项目,也可以参考这个方法。

C/C++编译和构建原理

当你创建了一个cpp源码文件时,这个文件在构建过程中,处于什么位置呢?

每个源代码文件都会被编译成一个.o结尾的目标文件,如果这个文件有main函数,则可以链接成可执行程序;没有main函数的话可以打包成静态库或者动态库,供别人的可执行程序使用。

1个.cpp文件对应1个.o文件,.h文件的内容会被include到.cpp中,所以.h可以看作不在编译过程中

多个没有main函数的.o文件,可以打包成一个静态库,也可以打包成一个动态库。

一个有main函数的.o文件,可以拿一些.o、.a、.so文件过来一起打包成一个可执行程序。

相关工具参考:

工具/概念 作用说明
g++ / clang++ 编译器,负责从 .cpp 编译成 .o 或链接为可执行文件
ld 链接器,负责将多个 .o 文件链接为可执行文件或库
as 汇编器,把 .s 文件转为 .o(有时作为中间步骤)
nm 查看 .o.a.so 文件中的符号(函数/变量名)
objdump 反汇编/查看二进制结构
readelf 查看 ELF 文件结构(更偏底层)
strip 去除调试符号,减小体积
ar 构建 .a 静态库(archive)
ldd 查看 ELF 的动态依赖库
file 查看文件类型,比如是不是 ELF
elfutils 一套处理 ELF 和 DWARF 调试信息的工具集

传统C++开发环境和依赖安装

假设你的项目中有2个cpp文件,其中一个有main函数,则构建打包时是这样的流程。如果你使用系统库/第三方库选择的是release静态链接,则会把.a文件里相关的.o全都拷贝到app中,这样编译出来的app文件占用硬盘空间较大一点。

而如果libcaaa你选择的是.so链接方式,则.so中的.o文件不会拷贝到app中,而是app启动时系统才去指定的目录加载.so文件一起运行,如果运行app时找不到.so文件,app就无法启动。这样打包的app,由于没有拷贝.so的内容进来,所以没有用.a链接的app占硬盘空间。

共享链接的好处是如果有10个不同的app使用了同一个.so,那同时运行这10个app就仅需要在内存里加载1份.so文件。现代计算机的内存、硬盘空间便宜、性能好,所以大多数时候会选择静态链接,而很少使用共享链接。

当然,如果你的项目中没有main函数,而是写一些库给别人用。那就不会去链接系统库,而是直接将.o文件打包成.a和.so,供别的项目使用。

系统库/第三方库的来源:

  1. apt/yum安装
  2. 自动手动编译源码并拷贝到系统库目录

docker和WSL2介绍

在个人学习C++或者在自己电脑上开发C++服务端程序时,经常遇到一些问题:

自己的电脑是windows系统,没法编译和运行linux系统的程序,我尝试过的解决办法有:

  1. 额外购买一台二手电脑装linux开发用;
  2. 租用linux云服务器,远程开发,最低配置的50元左右一个月;
  3. 自己的电脑装双系统,玩游戏时启windows,开发时启动linux;
  4. 在windows上安装vmware虚拟化软件,通过虚拟机运行Linux;
  5. 使用windows WSL1的ubuntu做开发;

上述方法都不是很灵活,但的确是我以前使用过的一些方法。

而现在有了一个更好的方案,就是docker,启动一个docker容器,在容器里面安装ubuntu环境,然后在这个ubuntu环境中进行开发。一般为每个C++项目创建一个docker环境。互不干扰,不同担心不同项目使用了不同版本的系统库。

但是docker是共享宿主机内核的,在windows系统上怎么能跑Linux的容器呢?答案是windows提供了WSL2机制,该机制相当于在windows内核中运行了一个linux内核。windows系统打开WSL2功能后,你的电脑就同时在运行windows和linux内核。有了这个linux内核,自然可以基于它来运行ubuntu环境的容器。

现在,当你在windows上安装docker desktop时,docker desktop默认就使用WSL2的linux内核来运行容器。

WSL2提供的linux内核对比vmware提供的linux内核有什么区别呢?

WSL提供的linux内核跟宿主机windows又更高的融合和共享能力,有更低的性能损耗。方便、高效的共享CPU/GPU/网络/硬盘等资源。并成为了docker和vscode的默认选择。不得不说微软考虑的还是很全面的。

而开发者需要做的,就是在自己电脑上打开WSL2功能(打开就会自动运行linux子系统了);在自己电脑上安装docker desktop,然后使用docker创建容器,容器默认就会运行在WSL的linux内核上。

这样,开发者即可通过vscode等IDE连接到容器中进行linux服务开发。同理,也可以在docker中运行mysql服务、redis服务、nginx服务、大语言模型等镜像,把部署中间件的工作也省了。

现代C++项目构建流程的栗子

接下来以一个C++开源项目举个实际的栗子,

这是一个linux上的高性能C++网络框架:https://github.com/scylladb/seastar,项目的README.md是这样写的:

第一步,运行install-dependencies.sh安装第三方依赖库,也就是前面说的那些.a和.so文件;

第二步,运行configure.py来生成build.ninja(类似makefile);

第三步,运行ninja(类似make,会调用gcc和ld等工具)进行编译;

如何在我的windows电脑编译运行它呢?

1.首先下载安装docker desktop:https://www.docker.com/products/docker-desktop/

安装docker-desktop过程中会打开windows的WSL2,当然你也可以手动打开WSL2:wsl.exe --update (注意,这一步可能出现各种网络失败,需要梯子)

2.下载seastar项目源码:git clone https://github.com/scylladb/seastar.git

3.可以看到,seastar项目提供了一个docker镜像用来进行编译,将seastar提供的dockerfile拷贝到根目录,并在根目录运行"docker build -t seastar-dev ."来构建docker镜像

4.镜像生成后,运行容器:

docker run -it seastar-dev /bin/bash

5.可以通过vscode或者docker-desktop界面,attach到该容器的shell中,在容器里下载seastar项目源码。

apt update
apt install git
git clone https://github.com/scylladb/seastar.git # 在容器中下载seastar项目代码
cd seastar # 进入项目
# ./install-dependencies.sh # 由于docker build时运行过安装依赖脚本了,这里不用再运行了
./configure.py --mode=release # 生成build.ninja文件
ninja -C build/release -j 4 # 4线程并发编译,产物生成到./build/release目录

6.debug: 运行configure.py时报错:seastar里面一个小工具程序依赖的libc-ares-dev版本不对,镜像中安装的是1.33版本,seastar要求不能用这个版本,解决办法:apt卸载已经安装的libc-ares-dev v1.33,手工下载v1.34或其他版本的源码,编译并安装:

apt remove libc-ares-dev
apt autoremove apt install -y wget wget https://github.com/c-ares/c-ares/releases/download/v1.34.5/c-ares-1.34.5.tar.gz # 下载该库的源码包 tar -xzf c-ares-1.34.5.tar.gz # 解压 cd c-ares-1.34.5
./configure --prefix=/usr # 生成Makefile文件,设置安装路径
make -j 4 # 4并发编译
make install # 安装到系统目录
ld /usr/lib/libcares.so /usr/lib/x86_64-linux-gnu/libcares.so # 为libcares.so文件建立软连接
ldconfig # 重新加载系统.so文件列表

结束

docker这种为每个程序、每个次编译环境都创建一个镜像环境的做法,极大的降低了环境准备的复杂性,虽然对硬件资源来说变得更浪费,但随着硬件性能提升、价格降低,这点浪费能带来开发效率的提升也是很划算的。特别是对于个人开发者来说。

windows也干脆直接选择集成了linux内核作为子系统,这样只要linux内核有的特性,在windows上同样能利用WSL享受到。

把这套能力直接套用在C++开发中,C++开发者也能专注代码开发,而不是把大部分研发时间用在研究环境搭建上。

C++服务开发环境-万事开头难的更多相关文章

  1. 万事开头难——Cocos2d-x学习历程(一)

    万事开头难,不知该从哪里开始,不过既然要学习一样新东西,那就从了解它开始吧... Cocos2d-x是一个通用平面游戏引擎,基于一个同样十分著名的游戏引擎Cocos2d-iPhone设计,Cocos2 ...

  2. 一个想法照进现实-《IT连》创业项目:万事开头难

    前言: 之前是一个想法,现在已经进入创业阶段,所以这个系列的标题,改了. 众筹的事在今天也停止了. 7-9号会在深圳龙岗布吉参加一个风投对接的活动,今晚(6号)会出发. 因为:在深圳会呆几天,而且这个 ...

  3. 万事开头难 && 实践出真知

    实践出真知,真是千古不变的真理. 前几天在顺手做一个万年历项目,实现了用TFT屏显示实时时间,日期,温度,和按键设置时间,能在特定时间显示特定的话语在显示屏上面.其实这个项目现在想想还是挺简单的.我的 ...

  4. 万事开头难,用HTML写的第一个界面,收获颇多

        很开心跟了叶老师学习和做项目,基础不好,前期他会帮你安排好学习路线和计划.前期没有项目做,叶老师先让我先学习jQuery,给我推荐了一些网站,叫我一边学习,一边写博客.其实很早就有想写博客的想 ...

  5. 构建微服务开发环境8————Hello 微服务

    [内容指引] 1.用IDEA打开微服务项目; 2.更新Maven依赖: 3.IntelliJ IDEA JDK配置; 4.修改代码: 5.运行微服务: 6.将代码变更提交到Github. 经过前面的努 ...

  6. 快速搭建 SpringCloud 微服务开发环境的脚手架

    本文适合有 SpringBoot 和 SpringCloud 基础知识的人群,跟着本文可使用和快速搭建 SpringCloud 项目. 本文作者:HelloGitHub-秦人 HelloGitHub ...

  7. 如何配置visual studio 2013进行负载测试-万事开头难

    声明:工作比较忙,文章写得不好,有时间再整理. 起因:最近众包平台因迁移到azure之后一直有网站慢的情况,让老板挨批了,但是测试环境一切正常,而且生产环境也没发现有卡顿和慢的情况,所以干脆来一次负载 ...

  8. 构建微服务开发环境1————如何安装JDK

    [内容指引] 下载JDK: Mac系统安装JDK: Mac系统配置环境变量: Windows系统安装JDK: Windows系统配置环境变量. 一.下载JDK 1.访问Oracle官网 http:// ...

  9. 构建微服务开发环境4————安装Docker及下载常用镜像

    [内容指引] 下载Docker: Mac下安装Docker: Windows下安装Docker; 下载常用docker镜像. 一.下载Docker 1.Mac适用Docker下载地址:https:// ...

  10. node服务开发环境判断和启动端口指定---process.env.NODE_ENV

    在node启动的时候我们需要在代码里面判断服务器运行环境 可以根据process.env.NODE_ENV来判断 一.开发环境的判断 1.安装 npm i -g cross-env 2.启动 cros ...

随机推荐

  1. Python+硅基流动API实现小说转有声读物

    一.注册硅基流动账号获取文本转语音api 1.注册登录硅基流动 注册.登录硅基流动 查看apikey 查看赠送的免费额度 点击文档中心 2.查看文本转语音api 查看文本转语音api 查看api使用指 ...

  2. 视图必须派生自 WebViewPage 或 WebViewPage 转

    以 ASP.NET MVC 5 为例. 遇见类似问题的蛮多的...

  3. frxpngimage单元的编译错误:frxpngimage left side cannot be assigned to

    一个老项目中,使用软数字录入数据,编译时出现n个:frxpngimage left side cannot be assigned to 原因是使用了frxpngimage单元,在D11中编译出现若干 ...

  4. 测试工作中用到的MongoDB命令

    1.远程连接MongoDB mongo host:port/dbname (host和port根据自己需要修改) 连接成功页面如下: 2.显示所有数据库 show dbs 3.切换到oversea-a ...

  5. python批量下载网易云音乐文件到本地

    现在听歌大多数只支持在线听,下载要钱,没网络就白搭了.好吧,用技术手段解决免费.下载.批量等一些列问题 整个脚本的逻辑和流程是,把歌曲地址都存在一个txt中,然后循环每次取一条链接,分析链接对应歌曲的 ...

  6. 多模态模型 Grounding DINO 初识

    简介 Grounding DINO 是一种先进的零样本目标检测模型,由 IDEA Research 开发.它通过将基于 Transformer 的检测器 DINO 与Grounded Pre-Trai ...

  7. 墨刀上线高级交互功能,能否超越Axure?

    引言 近期,国内主流原型设计工具墨刀推出了"变量.条件判断.函数"等功能,立刻在交互设计师与资深产品经理群体中引起热议.作为国产轻量级原型设计工具的龙头代表,墨刀早已俘获了中小团队 ...

  8. SpringBoot文件上传--转载

    转载地址:https://www.jianshu.com/p/85017f5ecba1

  9. docker容器中编辑文件报错bash: vi: command not found问题解决

    一.问题 在docker容器中想编辑mongodb的配置文件,然后用vi就报错了 bash: vi: command not found root@bbbbeb52:/conf# vi mongod. ...

  10. java基础之“在后端使用爬虫Jsoup工具根据标签id获取字符串中的标签html代码(java后端实现前端根据标签id获取标签对象)”

    一.场景 在电商项目中产品描述时必不可少的存在,每个不同的项目所需的描述不同,不能一概而论 在产品的描述中的部分数据是我们所需要的,如价格,尺码表等 如何在不依靠前端的前提下,完成数据的提取就成了问题 ...