C/C++ 头文件路径在编译时及工具中的设置

2023-11-14

使用 C/CPP, 避免不了要和各种头文件打交道, 系统库还好, 基本上不需要操心, 已经被自动预置入头文件列表中了. 棘手的是使用第三方库, 这时就要手动指定其头文件位置与库文件位置. 本文记录下在终端中手工编译与某些工具内编译的设置方式.

在这里插入图片描述

终端中使用 gcc/clang/makefile 手工编译

通常情况下, 我们可以使用 gcc -I/include -c test.c -o test.ogcc test.o -L/libs -o test 命令来分别指定头文件与库文件位置, 但是对于一个比较大的第三方库, 其头文件和库文件的数量是比较多的. 如果我们一个个手动地写, 那将是相当麻烦的. 所以, pkg-config 就应运而生了

简言之, pkg-config 为库提供编译与链接 flag 的功能.

pkg-config 安装

brew install pkg-config

pkg-config 常用命令

  • pkg-config --help: 查看帮助
  • pkg-config --list-all: 列出目前系统上所有支持 pkg-config 的库
  • pkg-config --cflags glib-2.0: 指定头文件
  • pkg-config --libs glib-2.0: 指定库文件

pkg-config 自然还有其他的功能, 可以通过 pkg-config --help 看到所有可用命令

使用 pkg-config 在终端进行编译

最基础的用法就是直接将 pkg-config --cflags --libs glib-2.0 作为 gcc 的参数之一写在其后.

# 注意 ` 是 grave/tilde 键, 不是单引号
$gcc main.c `pkg-config --cflags --libs glib-2.0` -o main

pkg-config 的原理及自定义位置

其实 pkg-config 所做的事情非常简单, 它通过第三方库定义的 .pc 文件进行头文件与库文件的定位, 例如 glib 的 pc 文件如下:

prefix=/usr/local/Cellar/glib/2.66.7
libdir=${prefix}/lib
includedir=${prefix}/include

bindir=${prefix}/bin
glib_genmarshal=${bindir}/glib-genmarshal
gobject_query=${bindir}/gobject-query
glib_mkenums=${bindir}/glib-mkenums

Name: GLib
Description: C Utility Library
Version: 2.66.7
Requires.private: libpcre >=  8.31
Libs: -L${libdir} -lglib-2.0 -L/usr/local/opt/gettext/lib -lintl
Libs.private: -Wl,-framework,CoreFoundation -Wl,-framework,Carbon -Wl,-framework,Foundation -Wl,-framework,AppKit -liconv -lm
Cflags: -I${includedir}/glib-2.0 -I${libdir}/glib-2.0/include -I/usr/local/opt/gettext/include

可以很清楚地看出, glib 在其 /usr/local/Cellar/glib/2.66.7/lib/pkgconfig/glib-2.0.pc 中已经定义好了相关的关键信息, 如 LibsCflags. 默认情况下 glib 会将其 pc 文件做一个软链接放置到 /usr/local/lib/pkgconfig
在这里插入图片描述

某些软件可能没有自动创建软链接的功能, 或者我们自定义一个 .pc 文件, 那么这时就需要在 .zshrc 中添加如下配置:

# 添加自定义的 pkg-config 路径, 默认的路径为 /usr/local/lib/pkgconfig
PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/opt/zlib/lib/pkgconfig
PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/opt/ruby/lib/pkgconfig
export PKG_CONFIG_PATH

这样当我们使用 gcc main.c 'pkg-config --cflags --libs zlib' -o main 的时候 pkg-config 就会自动找到相应的 .pc 文件了

vim 中配置头文件

youcompleteme 依赖的头文件路径

ycm 所依赖的补全依赖的头文件路径有:

  • 系统的 C_INCLUDE_PATH / CPP_INCLUDE_PATH

  • ~/.vimrc 中定义的 set path=***

  • ycm 中定义的 .ycm_extra_conf 文件

    ycm 的 .ycm_extra_conf.py 我通常定义在 .vimrc 中, 作为一个固定配置

    # ~/.vimrc
    let g:ycm_global_ycm_extra_conf = '~/.ycm_extra_conf.py' " 默认配置文件路径
    

    ~/.ycm_extra_conf.py 文件中, flags 表示我们使用的配置选项, 其中的 /usr/local/include 就代表了将 Homebrew 安装的头文件进行补全提示, 如果不够还可以直接添加自定义路径

    # ~/.ycm_extra_conf.py
    flags = [
    '-Wall',
    '-Wextra',
    '-Werror',
    '-fexceptions',
    '-DNDEBUG',
    '-std=c11',
    '-x',
    'c',
    '-isystem',
    '/usr/include',
    '-isystem',
    '/usr/local/include', # 重要, 通过 homebrew 安装的头文件大部分都在这里
    '-isystem',
    '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1',
    '-isystem',
    '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include',
    ]
    

    当然如果每个第三方库的路径都需要手动添加的话那就太麻烦了, 我们可以通过简单的一个 python 方法将系统的 pkg-config 输出作为路径导入到 flags

    # ~/.ycm_extra_conf.py
    # 通过 pkg-config 便捷添加头文件路径到 ycm 补全
    def pkg_config(pkg):
      def not_whitespace(string):
        return not (string == '' or string == '\n')
      output = subprocess.check_output(['pkg-config', '--cflags', pkg]).decode().strip()
      return list(filter(not_whitespace, output.split(' ')))
    
    flags += pkg_config('glib-2.0')
    

以上路径都可以起到辅助 ycm 进行补全的作用.

ale 所依赖的头文件路径

alelint 工具, 可以支持很多种语言. 实际上 ale 就是多种 linter 的一个集合平台, 针对于不同的语言提供了多种 linter 进行支持, 我们选择其中的一种即可. 比如我选择了 clangd 作为 c / cpp 的 linter. ale 对每一个 linter 都提供了设置选项, 自然 clangd 也不例外:

# ~/.vimrc
# 添加自定义的pkg-config路径, 默认的路径为 /usr/local/lib/pkgconfig
PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/opt/zlib/lib/pkgconfig
PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/opt/ruby/lib/pkgconfig
export PKG_CONFIG_PATH

CPPFLAGS+=$(pkg-config --cflags glib-2.0 zlib ruby-3.0)
export CPPFLAGS

CFLAGS+=$(pkg-config --cflags glib-2.0 zlib ruby-3.0)
export CFLAGS

LDFLAGS+="-I/usr/local/opt/openjdk/include"
LDFLAGS+=$(pkg-config --libs glib-2.0 zlib ruby-3.0)
export LDFLAGS
let g:ale_linters = {
            \   'c': ['clangd'],
            \   'cpp': ['clangd'],
            \   'markdown': ['markdownlint'],
            \}

let g:ale_c_clangd_options = $CFLAGS
let g:ale_cpp_clangd_options = $CFLAGS
let g:ale_markdown_markdownlint_options='-c $HOME/.markdownlint.json'

这里我在 ~/.zshrc 中使用 CFLAGS 导出自定义的 header 配置, 可以达到 一处定义, 多处使用的 的效果

编译运行所依赖的头文件路径

通常我使用 skywind3000/asyncrun 来执行相关 c / cpp 文件, 那么相关的头文件定义就很简单了, 直接在相关命令处加上 pkg-config 的相关参数即可, 如下:

map <F2> : call Run()<CR>

func Run()
    exec 'w'
    if &filetype == 'c'
        exec 'AsyncRun! gcc `pkg-config --cflags --libs glib-2.0` -Wall -O2 "$(VIM_FILEPATH)" -o "$HOME/.cache/build/C/$(VIM_FILENOEXT)" && "$HOME/.cache/build/C/$(VIM_FILENOEXT)"'
    elseif &filetype == 'java'
        exec 'AsyncRun! javac %; time java %<'
    elseif &filetype == 'sh'
        exec "AsyncRun! time bash %"
    elseif &filetype == 'python'
        exec 'AsyncRun! time python3 "%"'
    endif
endfunc

这样在 c 文件下, 只需要按下 <F2> 即可立即执行

Xcode 中配置头文件及库文件

TARGETS -> Build Settings -> Search Path -> Header Search Paths / Library Search Paths 中设置相应的 header 及库文件路径即可

在这里插入图片描述

总结

万变不离其宗, 虽然对于头文件与库文件有各种不同的配置方式, 但是都是围绕着如何方便地列出头文件与库文件的路径以供编译链接使用. 掌握了这个点, 我们即使在使用其他工具的时候也可以按照这个思路去尝试, 去解决.

参考

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

C/C++ 头文件路径在编译时及工具中的设置 的相关文章

  • 结构体如何存储在内存中?

    我有一个struct iof header在我的代码中 我确定它的宽度是 24 字节 我执行 sizeof iof header 它返回 32 字节宽 问题1为什么是 32 字节宽而不是 24 字节宽 问题2包括其成员在内 结构体如何存储在
  • 深拷贝和动态转换 unique_ptr

    假设我有一个如下所示的类 class A virtual A class B public A class C public A 我还有一个 unique ptr 向量 它是这样声明的 std vector
  • Dapper 在执行时挂起

    我有一个 IDb连接 sql UPDATE 表名 SET json json lastupdate SYSDATE WHERE id id var param new DynamicParameters param Add json jso
  • 嵌入资源文件的路径

    我的资源文件中有一个图标 我想引用它 这是需要图标文件路径的代码 IWshRuntimeLibrary IWshShortcut MyShortcut MyShortcut IWshRuntimeLibrary IWshShortcut W
  • 组合框下拉位置

    我有一个最大化的表单 其中包含 500px 的组合框控件 停靠在右上角 Width 尝试打开组合框后 列表的一半超出了屏幕 如何强制列表显示在表单中 棘手的问题 我找不到解决这个问题的好办法 只是一个解决方法 添加一个新类并粘贴如下所示的代
  • 如何将 Q 格式整数转换为浮点数(反之亦然)?

    我四处搜寻 找不到一个很好的问题来回答这个问题 给定一个整数 使用Q Format https en wikipedia org wiki Q number format 如何将该数字转换为普通浮点类型 反之亦然 如何将浮点类型转换为Q F
  • 在c#中获取没有时间的日期

    我的表上有一列 缺勤日期时间 日期 当我想要获取包含日期的行时 它返回 0 行 这是我的 C 代码 DateTime ClassDate DateTime Parse lblDate Content ToString var Abs dbs
  • 如何将STL容器数据转储到gdb中?

    我无法在 gdb 中转储 STL 无序映射容器值 变量类型是 std unordered map var 我的 gdb 版本 7 7 1 GDB配置 configure host x86 64 linux gnu target x86 64
  • 处理“未找到细胞”。 Excel 中的错误

    我正在使用 Excel VSTO 应用程序并使用以下代码在工作表中查找错误单元格 Excel Range rngTemp Excel Range rngErrorRange Excel Worksheet Sheet1 Excel Work
  • 使用数据绑定,如何将包含表情符号的文本绑定到标签并使其正确显示?

    我正在编写一个应用程序来连接 WordPress BuddyPress API 该应用程序将允许用户通过 API 相互发送消息 当这些消息包含表情符号时 我很难正确显示它们 以下是 API 返回的消息文本的简短示例 Hi x1f642 ho
  • C#:自定义转换为值类型

    是否可以将自定义类转换为值类型 这是一个例子 var x new Foo var y int x Does not compile 是否有可能实现上述情况 我需要超载一些东西吗Foo 您将必须重载强制转换运算符 public class F
  • 如何在 C# 中更改公共 IP 地址

    我正在创建一个 C winform 应用程序 我想在其中更改公共 IP 地址 而不是像 Hotspot Shield ZenMate OpenVPN 等那样更改 IPv4 地址 我已经检查了以下链接 但没有找到足够的帮助 所以我发布了这个问
  • 从 DataRow 单元格解析 int [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 如何从 DataRow 单元格解析 int 值 Int32 Parse item QuestionId ToString 这段代码可以工作 但看
  • valgrind 在 Raspberry Pi 上返回未处理的指令

    我最近一直在尝试在运行 Debian GNU Linux7 0 喘息 的树莓派 型号 b 上使用 valgrind 来调试分段错误 每次我在编译的 C 程序上运行 valgrind 时 都会得到类似以下内容的信息 disInstr arm
  • Type.GetInterfaces() 仅适用于声明的接口

    首先 像这样的问题有很多 也许有些OP甚至在问同样的问题 问题是这些问题的答案 无论是否接受 都没有真正回答这个问题 至少我找不到 如何确定类直接声明的接口 而不是由父级或声明的接口继承的接口 e g interface I interfa
  • C++ 中是否有与 PHP 的explode() 函数等效的函数? [复制]

    这个问题在这里已经有答案了 可能的重复 在 C 中分割字符串 https stackoverflow com questions 236129 splitting a string in c 在 PHP 中 explode 函数将获取一个字
  • 选择合适的IDE

    您会推荐使用以下哪种 IDE 语言来在 Windows 下开发涉及识别手势并与操作系统交互的项目 我将使用 OpenCV 库来执行图像处理任务 之后 我将使用 win32 API 或 NET 框架与操作系统交互 具体取决于您建议的工具 性能
  • 具有四个 && 的 LINQ Where 子句

    我正在尝试在Where 子句中创建一个带有4 个参数的LINQ 查询 这是一个 Windows 8 应用程序项目 我正在使用 SQLite 数据库 SQLite 实现 https github com praeclarum sqlite n
  • 从对列表创建邻接列表类型结构

    在 C 中 我有 class Pair int val1 int val2 我有一个来自以下来源的配对列表 List
  • 如何在 C 中创建最低有效位设置为 1 的掩码

    这个功能如何运作 最低有效 n 位设置为 1 的掩码 Example n 6 gt 0x2F n 17 gt 0x1FFFF 我根本不明白这些 尤其是 n 6 gt 0x2F 另外 什么是面膜 通常的方法是采取1 并将其左移n位 这会给你类

随机推荐

  • 使用ChatGPT的方式与在其他地方使用它的方式基本相同。以下是一些步骤:

    在中国使用ChatGPT的方式与在其他地方使用它的方式基本相同 以下是一些步骤 访问OpenAI的官方网站 OpenAI 在网站上找到GPT 3或ChatGPT的相关信息 OpenAI提供了详细的API文档 可以帮助你理解如何使用它们 你需
  • mysql数据库之跨表复制

    背景说明 目标库 target db 目标数据表 target tb 将目标库的制定表复制到当前数据库中 包括一下几个方面 一 表结构复制 仅仅复制了表的结构 没有数据 create table current db new tb like
  • Logitech G系鼠标脚本编程,实现鼠标自动定位控制

    利用罗技官方提供的API来写一个鼠标自动定位移动脚本 点击脚本编辑器中的帮助选项 查看罗技官方提供的API说明 有很多实现好的鼠标功能 G series Lua API V8 45 Overview and Reference 下面是我写的
  • 深入解析SpringBoot启动原理

    1 启动类中的SpringApplication run方法会创建一个SpringApplication的实例 并做一些初始化工作 SpringBootApplication Slf4j public class HuotuUserServ
  • Linux C编程基础:获取时间

    1 前言 对于linux下的编程 无论是用户态还是内核态 时间获取都是经常需要使用到的 以下分别从用户态和内核态整理了几个常用的时间获取接口 供编写代码时快速查阅 linux时间子系统的发展历史及详细介绍 可以参考 深入理解Linux时间子
  • stm32 机械周期_STM32定时器周期计算

    STM32定时器周期计算 公式是 1 TIM Prescaler 时钟 1 TIM Period F103配置生成1ms的时钟 1 35 36M 1 999 1MS TIM TimeBaseInitTypeDef TIM TimeBaseS
  • LeNet-5识别数字

    LeNet识别数字 前言 环境 实现 结果 前言 实现经典卷积神经网络LeNet LeNet 5 识别数字 这里将激活函数从sigmoid换成ReLU 参考资料 动手学深度学习 环境 python pytorch 实现 import tor
  • 设计模式八大原则知多少

    设计模式是一种通用的解决问题的经验 可以帮助我们设计出可重用 可维护和可扩展的软件 在设计模式中 有八个常见的原则 它们是 单一职责原则 SRP Single Responsibility Principle 一个类应该只有一个引起变化的原
  • AlexNet(深度学习模型)详解

    AlexNet是一种深度卷积神经网络 由Alex Krizhevsky Ilya Sutskever和Geoffrey Hinton于2012年在ImageNet图像分类竞赛中首次引入 这项竞赛是一个庞大的数据集 其中包含超过100万张图像
  • TP5学习(十三):其他

    一 缓存 设置 缓存支持采用驱动方式 所以缓存在使用之前 需要进行连接操作 也就是缓存初始化操作 options 缓存类型为File type gt File 缓存有效期为永久有效 expire gt 0 缓存前缀 prefix gt th
  • 快速排序和快速选择

    用同样的划分 完成不同的目的 快速排序在 的平均时间复杂度完成排序 快速选择在 的平均时间复杂度找出第 k 大的元素 因为 quickSelect 只需要对划分的其中一边递归 int partition int a int l int r
  • 如何在visio2010的框图中插入公式?

    如何在visio2010的框图中插入公式 其实很简单 也没必要下载Mathtype 先在world中用自带的公式编辑器将公式写好 如下图 此时选中公式 博文已经迁移到个人主页https guangmujun cn archives 143
  • SpringAOP+自定义注解模拟shiro框架实现

    一 概念 权限管理就是管理用户对于资源的操作 本 CRM 系统的权限 也称作资源 是基于角色操作权限来实现的 即RBAC Role Based Access Control 基于角色的访问控制 就是用户通过角色与权限进行关联 简单地说 一个
  • iOSWebview与js交互之调整字体大小

    先看效果图 iOS开发经常会跟Webview交互 主要调用的就是stringByEvaluatingJavaScriptFromString这个方法 也可以在 BOOL webView UIWebView webView shouldSta
  • NAT网关和NAT穿越原理

    转自 https blog csdn net chance yin article details 37913963 一 原理图 1 背景信息 1 我们模拟的情形是位于网络A下的内网主机UserA 想要和位于网络B下的内网主机UserB进行
  • 网页HTML5制作flex布局骰子,CSS3的Flexbox骰子布局的实现及分析

    这篇文章主要介绍了关于CSS3的Flexbox骰子布局的实现及分析 有着一定的参考价值 现在分享给大家 有需要的朋友可以参考一下 骰子布局顾名思义 就是好比骰子的一面最多可以放置9个点 而每个面放置的点数正好就是一个布局的模型图 这里我们就
  • 网站漏洞怎么修复代码漏洞

    jeecms 最近被爆出高危网站漏洞 可以导致网站被上传webshell木马文件 受影响的版本是jeecms V6 0版本到jeecmsV7 0版本 该网站系统采用的是JAVA语言开发 数据库使用的是oracle mysql sql数据库
  • python 类self详解

    class Box object def init this boxname size color this boxname boxname this size size this color color self就是用于存储对象属性的集合
  • PnP 问题

    欢迎访问我的博客首页 PnP 问题 1 DLT 2 P3P 3 G2O 求解 PnP 3 1 单目 3 2 双目 4 自定义顶点与边优化内参 4 1 二元边 4 2 三元边 4 3 总结 5 参考 PnP Perspective n Poi
  • C/C++ 头文件路径在编译时及工具中的设置

    使用 C CPP 避免不了要和各种头文件打交道 系统库还好 基本上不需要操心 已经被自动预置入头文件列表中了 棘手的是使用第三方库 这时就要手动指定其头文件位置与库文件位置 本文记录下在终端中手工编译与某些工具内编译的设置方式 终端中使用