目录
1.<>和""的含义
背景:#include<>和#include""的区别困扰了我很久,网上的说法亦不明朗,于是决定做实验探究(by ubuntu, CMake)
实验结果:
<>的搜索范围=系统目录(含临时);" "的搜索范围=该文件的相对路径+<>的搜索范围
解释:
① 什么叫该文件的相对路径?
即该#include命令所在的文件的相对路径。我们现有一个文件夹Test,结构如下
Test
├── out_file.h
└── test_inner
├── CMakeLists.txt
├── haha.cc
├── haha.h
├── include
│ └── include.h
├── main.cc
└── src
└── src.h
3 directories, 7 files
那么,CMakeLists关于头文件什么也不设置,在main.cc里,你可以直接
#include "haha.h"
#include "src/src.h"
#include "include/include.h"
#include "../out_file.h"
同理,在include.h里,你可以直接
#include "../haha.h"
#include "../src/src.h"
#include "../../out_file.h"
简单点说,就是要引用文件对该文件的相对路径,只要你愿意,写个“../../../../fxxk.h”跑到很远的地方去找,也可以
②什么叫系统目录?
实质是编译器预处理的默认搜索目录,指令如下所示
echo | g++ -v -x c++ -E - // 打印gcc预处理c++的默认目录
echo | gcc -x c -v -E - // 打印gcc预处理c的默认目录
echo | clang -x c++ -v -E - // 打印clang预处理c++的默认目录
我电脑里(Ubuntu 18.04),打印gcc预处理c++的默认目录的结果如下
#include "..." search starts here:
#include <...> search starts here:
/usr/include/c++/7
/usr/include/x86_64-linux-gnu/c++/7
/usr/include/c++/7/backward
/usr/lib/gcc/x86_64-linux-gnu/7/include
/usr/local/include
/usr/lib/gcc/x86_64-linux-gnu/7/include-fixed
/usr/include/x86_64-linux-gnu
/usr/include
End of search list.
换句话说,你随便写个"fxxk.h"放在这些文件夹之一,也可以直接
#include <fxxk.h>
③“系统目录(含临时)”中的“临时”是什么意思?
记不记得,CMakeLists里,我们经常会添加头文件目录——调用include_directories指令。
这个指令底层上是改变了什么?
就是暂时性地将include_directories指令提到的路径,加在系统目录之后,只在本次Cmake有效(但我还不知道怎么去证明这件事)
所以,只要你在include_directories把源码涉及的文件夹全包含一遍……头文件你可以全写<>(不重名的前提下)
④有同名怎么办?
按顺序,先找到哪个用哪个。<>搜索时,按系统目录顺序搜索,""搜索时,先搜相对路径,再搜系统
2.抠库-OSQP为例
很多库我们不都是直接安装的嘛,但实际上,除去很复杂的,相当一部分库的安装,只是把头文件放进系统目录,把库文件也放进系统目录,以OSQP库为例,下面演示怎么全抠出来并使用。
好处:女朋友:“我要用OSQP!”你:“安装啊。”女朋友:“我不!我不装!我要直接跑!”你:“我给你封个docker。”女朋友:“不,我不要docker,我就要直接跑!”你:“……”(哦不,我没有女朋友。但我是打工人啊,公司可不允许交一个安库才能运行的代码)
步骤1:OSQP和OSQP-Eigen安装
安装步骤详见:qp solver
安装它们的最后一步(sudo make install),你会看到如下代码(以OSQP为例)
由于我以前安过,所以写的up-to-date,第一次安应该是Installing
然后你就发现了,头文件被安装在/usr/local/include/osqp和/usr/local/include/qdldl两个文件夹下,库文件在/usr/local/lib下,有4个。OSQP-EIGEN也是同理。
步骤2:把头文件和库文件抠出来,并写CMakeLists
现在我们的文件结构如下,其中抠出来的头文件和库文件分别放在了自建的对应文件夹的include和lib文件夹下(Eigen也是同理,我也抠了)
3rdparty_test
├── 3rdparty
│ ├── Eigen
│ │ ├── Eigen
│ │ ├── signature_of_eigen3_matrix_library
│ │ └── unsupported
│ ├── osqp
│ │ ├── include
│ │ └── lib
│ └── osqp-eigen
│ ├── include
│ └── lib
├── CMakeLists.txt
└── main.cpp
然后CMakeLists加的关键几行如下,都很常规(分别是添加头文件目录,添加库文件目录,生成可执行文件,链接库),很好理解
include_directories(3rdparty/osqp/include 3rdparty/Eigen 3rdparty/osqp-eigen/include)
LINK_DIRECTORIES(3rdparty/osqp/lib 3rdparty/osqp-eigen/lib)
add_executable (${PROJECT_NAME} main.cpp)
TARGET_LINK_LIBRARIES(${PROJECT_NAME} libosqp.so libosqp.a libOsqpEigen.so)
步骤3.开干
这个时候,你就可以回到之前的抠库的地方,把系统里这几个库的文件全部删了!!!
然后,#include它们,看跑不跑得通
main.cpp的头文件包含如下所示
#include "osqp.h"
#include "Eigen/Core"
#include "Eigen/Dense"
#include "OsqpEigen.h"
这个时候你发现可能能跑通,抠库成功??
不是,还不能打包发给女朋友,因为大概率是你删系统库还没删干净,比如你打开osqp-eigen.h,开头是这样写的
/**
* @file OsqpEigen.h
* @author Giulio Romualdi, Stefano Dafarra
* @copyright Released under the terms of the BSD 3-Clause License
* @date 2018
*/
#ifndef OSQPEIGEN_OSQPEIGEN_H
#define OSQPEIGEN_OSQPEIGEN_H
#include <OsqpEigen/Constants.hpp>
#include <OsqpEigen/Data.hpp>
#include <OsqpEigen/Settings.hpp>
#include <OsqpEigen/Solver.hpp>
#include <OsqpEigen/SparseMatrixHelper.hpp>
#endif //OSQPEIGEN_OSQPEIGEN_H
按道理来说,这是找不到的,我们需要把它们改成(或者改目录结构)
#include "Constants.hpp"
#include "Data.hpp"
#include "Settings.hpp"
#include "Solver.hpp"
#include "SparseMatrixHelper.hpp"
或
#include <Constants.hpp>
#include <Data.hpp>
#include <Settings.hpp>
#include <Solver.hpp>
#include <SparseMatrixHelper.hpp>
当你把每个头文件(或目录结构)都改好时,就真的抠出来了,能打包发女朋友啦!
发之前,你可以先把整个文件夹拷出来,放到一个新建的啥也没有的虚拟机里跑跑,没bug就是零卡!
我自己把每个文件的头文件都改好了,并在新的虚拟机里测试过能跑的代码放在下面链接里了,希望对路过的人有所帮助。也希望我早日找到女朋友o(╥﹏╥)o
3.代码
链接: 某度 /s/17Zl4_kBgZr8cQhr77yuuyQ
提取码:oobk