使用 C/CPP
, 避免不了要和各类头文件打交道, 系统库还好, 基本上不须要操心, 已经被自动预置入头文件列表中了. 棘手的是使用第三方库, 这时就要手动指定其头文件位置与库文件位置. 本文记录下在终端中手工编译与某些工具内编译的设置方式.html
一般状况下, 咱们可使用 gcc -I/include -c test.c -o test.o
与 gcc test.o -L/libs -o test
命令来分别指定头文件与库文件位置, 可是对于一个比较大的第三方库, 其头文件和库文件的数量是比较多的. 若是咱们一个个手动地写, 那将是至关麻烦的. 因此, pkg-config
就应运而生了java
简言之, pkg-config
为库提供编译与连接 flag 的功能.python
brew install 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
看到全部可用命令c++
最基础的用法就是直接将 pkg-config --cflags --libs glib-2.0
做为 gcc 的参数之一写在其后.git
# 注意 ` 是 grave/tilde 键, 不是单引号
$gcc main.c `pkg-config --cflags --libs glib-2.0` -o main
复制代码
其实 pkg-config 所作的事情很是简单, 它经过第三方库定义的 .pc
文件进行头文件与库文件的定位, 例如 glib
的 pc 文件以下:github
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
中已经定义好了相关的关键信息, 如 Libs
及 Cflags
. 默认状况下 glib
会将其 pc 文件作一个软连接放置到 /usr/local/lib/pkgconfig
中json
某些软件可能没有自动建立软连接的功能, 或者咱们自定义一个 .pc
文件, 那么这时就须要在 .zshrc
中添加以下配置:vim
# 添加自定义的 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
文件了ruby
ycm 所依赖的补全依赖的头文件路径有:bash
系统的 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
是 lint
工具, 能够支持不少种语言. 实际上 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>
便可当即执行
在 TARGETS
-> Build Settings
-> Search Path
-> Header Search Paths
/ Library Search Paths
中设置相应的 header 及库文件路径便可
万变不离其宗, 虽然对于头文件与库文件有各类不一样的配置方式, 可是都是围绕着如何方便地列出头文件与库文件的路径以供编译连接使用. 掌握了这个点, 咱们即便在使用其余工具的时候也能够按照这个思路去尝试, 去解决.