管理C++的第三方库以及编译

第三方库这个说法,不知道出自哪里,但一般是指开发者,系统/平台提供商之外的第三个参与者提供的程序库。
大多数开源软件库在软件系统中都是第三方库。

完全不使用库的开发,在90年代就已经被放弃了,特别MFC/OWL/QT这些先行者。开源运动的兴起使得第三方库
成为主力使用库。

C++领域有一些非常特殊的库,比如早期的STLport和当前的Boost,它们就像是语言的事实标准,基本在每个程序
中都可以见到他们的身影。

但第三方库也会导致相当多的问题,主要总是包括:

  1. 版本不一致。同一个软件系统中,如果引用了同一个第三方库的两个不同版本,那一定会暗生问题。
  2. 编译选项不一致。一般为了减少编译时间,第三方库都会以编译后的.a/.lib形式参与软件编译,第三方库的编译选项与软件系统的编译选项不同,也是会有一些潜在的问题。特别是x86/x64,ansi/utf-8这些选项不同,根本就不能用。
  3. 版本管理库变大。在一些大项目中常常会有几个G的版本库,每次clone代价很大。其实很多都是第三方库,不同版本,不同编译选项生成的库引入。

除了把编译的库引入项目,也有人以源代码的形式引入开源软件,比如GCC、SDL、WxWights、QT。如果第三方库本身编译不复杂,原代码也很简单,这么做比较好。

但是像Boost.Thread这样的库,就不行了(它需要编译成动态库,静态引用会有问题)。

另一方面,如果第三方库升级,就是一个比较复杂的工程,如果不升级,又只能看着第三方库的问题得不到解决。

在Linux上这个问题并不严重,系统级的软件管理工具可以代管大多数的第三方。比如debian系的,可以使用apt得到大多数的开源库,同时如果需要最新版本,也可以通过第三方源来取得。

在交叉编译和window平台上这个问题就非常头痛了。我们需要从几个层次来解决这个问题。

  1. 需要有中心化的第三方源代码获取平台,这个平台需要支持按用户/组织+第三方库+版本的形式取得源代码,同时还需要保证及时跟踪来源。这个类似于bintray/github都可以。公司内部可以使用gitlab来搭建。
  2. 需要有一个构建脚本平台,存放在不同工具链和平台的情况下,这个脚本可以从源代码中心的源代码,把源代码编译成库。同样可以用github这类工具搭建和管理。
  3. 在项目中提供一个配置文件,需要的开源库(只需指定编译脚本,脚本是针对开源库)。这个只需要一个文本文件即可。
  4. 在开发者的机器和编译服务器上,下载编译脚本,生成库。源代码、最终结果可以缓存在本机上。可以使用项目原本的构建工具。

如果只考虑windows+vc这个工具链,最简单的工具是使用msbuild,即为第三方库构建工程,编译结果生成成为vcprops文件,由项目引用。在项目工程中,可以通过prebuild过程加上下载、编译、安装第三方库的过程,因为有缓存,每台机器上应该只需要做一次。

考虑Boost这个最常用的库,并没有一个msbuild可以调用工程,这个方案通用性很差。但对于只使用vc的公司还是非常实用。因为只需要一个内源的源代码管理工具就可以了,没有git甚至可以用svn。

如果有多平台交叉编译,要考虑先统一项目自己的编译工具,使用CMake/Scons/Gyp这些跨平台编译工具,否则需要在不同的编译工具下都做一套。

以CMake为例,最接近这个系统的是CPM这个工具,它用github做前两个服务器,CMake的脚本来完成下载,编译。但受CMake脚本的能力限制,它无法完成更复杂的版本管理工作,只能做为一个试验原型。

使用CPM,可以先把自己的项目改成使用CMake编译,在CMakeLists.txt中引入CPM语句,再引入需要的第三方库。如果第三方库已经在有一个CPM脚本工程,就很简单直接引用即可。但如果没有,就需要自己先建立CPM脚本工程。即一个CMakeLists.txt,可以下载编译第三方库,再提供CPM一些专用宏,以便后续项目能找到这个第三方库。

一个内源第三方库(指公司内共享库)需要两个git工程(或svn目录),一个提供原始代码和维护工作,另一个提供构建脚本,这个脚本甚至可以是专用于某个项目。最后需一个工具能下载,脚本调用,缓存管理这些工作。

基于C++社区不自己发明工具传统,以及cmake/git的流行程度,我考虑使用bash来完成这个部分。基本数据结构设计如下:

CPM_HOME 做为根目录
sources 源代码下载
hosts 下载服务器
groups 用户或组织
library-name 库
scripts
hosts 下载服务器
groups 用户或组织
library-name 库, 源代码构建完成后会安装到这个目录下
bin 二进制结果,包括可执行文件
include 头文件,一般应支持多配置
lib/xx/ 应对不同的配置,参考boost library
flags/xx/ 应对不同的配置,需导出一些编译选项
build
构建目录,对于不支持外部构建目录的开源软件,可以选择复制过来in-source构建
考虑并发构建,应在这里文件锁定操作。
除了锁定目录外,其它目录可以删除以减少空间占用。

repos
project-id 成生特定于项目第三方库包,这样项目只需要引入一个第三方目录。

以上目录都会在本地保存一个hash文件以保持完整和不变性。

类似python我们使用 requirements.txt 项目的需求第三方库,使用cpp_setup requirements.txt来完成预建编译环境。
requirements使用
[host:port/]username/cpm-library-name
全局配置中,可以默认的host:port。这里可以不写host:port。
这里是指向特定的构建脚本,脚本能支持哪些平台,哪些发布版本,哪些运行时库都由脚本自己决定。缺少项目需要的配置时,只会编译失败。

如果项目支持CMake,那么只需要引入CPM即可。

如果项目可以要求生成一个project-id目录来聚合第三方库,方便make/vc++这些工具集成。

C++程序的目录结构、编译、打包、分发的更多相关文章

  1. Android程序的目录结构

    本篇文章我们将介绍Android应用程序的目录结构.本目录下有如图的目录结构: 下面我们来一 一介绍: 1.     Src:该目录中存放的是该项目的源代码 2.     Gen:该目录下的文件全部都 ...

  2. 3-微信小程序开发(小程序的目录结构说明)

    https://www.cnblogs.com/yangfengwu/p/10050784.html 源码下载链接: 或者 这节先说一下小程序的目录结构 自行根据  https://www.cnblo ...

  3. 微信小程序基本目录结构学习

    今天我们就以firstdemo为例,介绍一下小程序的基本目录结构.当我们打开一个微信小程序项目后,点击进入“编辑”菜单,我们可以看到有以下5个文件/文件夹):pages文件夹,utils文件夹,全局文 ...

  4. 大型Vuex应用程序的目录结构

    译者按: 听前端大佬聊聊Vuex大型项目架构的经验 原文: Large-scale Vuex application structures 译者: Fundebug 为了保证可读性,本文采用意译而非直 ...

  5. 微信小程序之目录结构

    小程序,功能不会太多,页面不会太多. 正常情况下,会包含首页,分类页面,个人中心页面,导航页面,其他页面等等. 我们首先要把页面结构布置好,把架子搭建好. 剩下的就是配置一些内容,小程序的基本信息,接 ...

  6. 小程序的目录结构/配置介绍/视图层wxml数据绑定/双线程模型/小程序的启动流程

    安装好微信小程序开发软件,创建项目 小程序文件结构和传统web对比 结构 传统web 微信小程序 结构 HTML WXML 样式 CSS WXSS 逻辑 Javascript Javascript 配 ...

  7. 微信小程序的目录结构解剖

    在微信小程序当中,我们看到有: .js后缀文件,.json后缀文件,.wxss后缀文件,.wxml后缀文件 .js后缀文件就是我们写的普通的js文件 .json后缀文件就是小程序的配置文件,比如:wi ...

  8. Android开发:程序目录结构详解

    HelloWorld程序的目录结构概述 我们可以在文件夹中看到,HelloWorld程序的目录主要包括:src文件夹.gen文件夹.Android文件夹.assets.res文件夹. AndroidM ...

  9. Tomcat的目录结构及部署应用程序

    下载好的二进制的Tomcat,解压会看到7个目录,如下: bin 目录:Tomcat的脚本存放目录,如启动.关闭脚本等.其中 **.bat用于windows平台,**.sh用于Linux平台 conf ...

随机推荐

  1. 小程序切换账户拉取仓库文件的appid提示

    小程序切换账户拉取仓库文件,拉取后appid会提示项目不是当前appid的项目,因为切换了账户,而每个小程序账户只有一个appid,所以会冲突 去project.config.json里吧appid改 ...

  2. JS Date日期

    //日期属性var td = new Date(); alert( "getDate():" +td.getDate()+"\n" + "getDay ...

  3. shell脚本,每5个字符之间插入"|",行末不插入“|”

    文本aaaaabbbbbcccccddddeeeeefffffkkkkkvvvvnnnnnggggg 希望得到的结果如下:aaaaa|bbbbb|ccccc|ddddeeeee|fffff|kkkkk ...

  4. 求小球反弹高度,及落地过程中经过的路程~~~java代码

    总结:这种思想,不是一想就突然出现在脑海里的 package com.c2; //题目:一球从100米高度自由落下,每次落地后反跳回原高度的一半: //再落下,求它在 第10次落地时,共经过多少米?第 ...

  5. 过河卒(Noip2002)(dp)

    过河卒(Noip2002) 时间限制: 1 Sec  内存限制: 128 MB提交: 7  解决: 6[提交][状态][讨论版][命题人:quanxing] 题目描述 棋盘上A点有一个过河卒,需要走到 ...

  6. php获取当前月月初至月末的时间戳,上个月月初至月末的时间戳

    当前月 <?php $thismonth = date('m'); $thisyear = date('Y'); $startDay = $thisyear . '-' . $thismonth ...

  7. Three.js创建运动立体几何体示例

    效果图 安装 帧率统计工具 变量控制GUI demo 效果图 安装 npm install three 帧率统计工具 // 监听动画帧率 var Stats = function () { var m ...

  8. Java 查询数据后进行递归操作

    java的递归方法记录: private List<Map<String, Object>> generateOrgMapToTree(List<Map<Strin ...

  9. K12(在线学习的平台)

    项目:K12(在线学习的平台) 一.背景 目的是做一个在线的学习平台,提高学生的课程完成度 K12:大目标是要取代线下班 - 录制专门的视频 - 导师的监管:如果没有主动和那个学生聊天,就扣钱 - 学 ...

  10. HIVE UDF

    基本函数 SHOW FUNCTIONS; DESCRIBE FUNCTION <function_name>; 日期函数 返回值类型 名称 描述 string from_unixtime( ...