假设我在linux下载一个库并构建它:configure,make,sudo make install。
该库附带了我想要包含在项目中的标题。编译器如何知道在哪里搜索头文件?
gcc -print-prog-name=cc1plus
-v是否有其他机制来注册我未考虑过的标题位置?这些组合方法是否为我提供了全面的视图,或者换句话说,如果我看看这些地方,我是否已经看到所有可以看到的,假设我正在使用gnu-make?最后,是否有一种方便的方法让Make向我展示它正在检查标题的位置?
背景:我正在处理的库是zeromq和google的协议缓冲区。平台是CentOS。编译器抱怨它无法找到标头。我在代理系统(Fedora)上构建了这个程序,它似乎不需要额外的干预来确保这些头文件是可访问的。
在Linux(或其他类似unix的OS)中注册头搜索位置没有通常的机制。
GCC是为您的系统类型构建的,具有每个C和C ++的预处理器搜索目录的默认列表。您可以使用命令(以及其他)显示C的列表:
$ gcc -x c -E -Wp,-v -
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/8/../../../../x86_64-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/x86_64-linux-gnu/8/include
/usr/local/include
/usr/lib/gcc/x86_64-linux-gnu/8/include-fixed
/usr/include/x86_64-linux-gnu
/usr/include
End of search list.
...
$ [CNTL-C]
对于C ++:
$ gcc -x c++ -E -Wp,-v -
ignoring duplicate directory "/usr/include/x86_64-linux-gnu/c++/8"
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/8/../../../../x86_64-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/include/c++/8
/usr/include/x86_64-linux-gnu/c++/8
/usr/include/c++/8/backward
/usr/lib/gcc/x86_64-linux-gnu/8/include
/usr/local/include
/usr/lib/gcc/x86_64-linux-gnu/8/include-fixed
/usr/include/x86_64-linux-gnu
/usr/include
End of search list.
...
$ [CNTL-C]
请注意,C和C ++的默认搜索目录是不同的:C ++ - 列表是C列表的超集。当您以正常方式编译C源文件时,将搜索C列表:
gcc [options...] foo.c ...
当您以通常的方式编译C ++源时,将搜索C ++列表:
g++ [options...] foo.cpp bar.cc gum.cxx ...
只有两种方法可以将头搜索目录传递给预处理器: -
您可以使用以下选项之一在命令行中显式指定搜索目录:
-I dir
-iquote dir
-isystem dir
-idirafter dir
按照the manual: 3.15 Options for Directory Search
或者,您可以在预处理器将其解释为搜索目录列表的其中一个环境变量的设置中列出搜索目录。对于C,这些是:
CPATH
C_INCLUDE_PATH
对于C ++,它们是:
CPATH
CPLUS_INCLUDE_PATH
按照the manual: 3.20 Environment Variables Affecting GCC
通过在一个根权限文件/etc/environment
,/etc/profile
,/etc/profile.d/
,/etc/bash.bashrc
中定义环境变量,可以在Linux中为环境变量提供持久的默认系统范围定义。因此,如果某个代理将其中一个文件中的CPATH
和/或C_INCLUDE_PATH|CPLUS_INCLUDE_PATH
定义为:
-punctuated目录列表,那么这些目录将有效地将这些目录注册为C | C ++的GCC搜索目录。但是,GCC安装不会安装任何此类设置:它们只能由root用户手动设置。您可以检查,如果您绘制一个空白,那么这些变量只有在瞬态shell中定义时才有影响。它们在构建系统中的使用非常罕见,正是因为它们在操作环境中引入了不透明的依赖性。
我上面用来列出默认搜索目录的命令对于通过两种可能的方法之一添加非默认目录很敏感:
$ mkdir my_include
$ gcc -x c -I my_include -E -Wp,-v -
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/8/../../../../x86_64-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
my_include
/usr/lib/gcc/x86_64-linux-gnu/8/include
/usr/local/include
/usr/lib/gcc/x86_64-linux-gnu/8/include-fixed
/usr/include/x86_64-linux-gnu
/usr/include
End of search list.
要么:
$ gcc -x c -iquote my_include -E -Wp,-v -
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/8/../../../../x86_64-linux-gnu/include"
#include "..." search starts here:
my_include
#include <...> search starts here:
/usr/lib/gcc/x86_64-linux-gnu/8/include
/usr/local/include
/usr/lib/gcc/x86_64-linux-gnu/8/include-fixed
/usr/include/x86_64-linux-gnu
/usr/include
End of search list.
要么:
$ export CPLUS_INCLUDE_PATH=my_include
$ gcc -x c++ -E -Wp,-v -
ignoring duplicate directory "/usr/include/x86_64-linux-gnu/c++/8"
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/8/../../../../x86_64-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
my_include
/usr/include/c++/8
/usr/include/x86_64-linux-gnu/c++/8
/usr/include/c++/8/backward
/usr/lib/gcc/x86_64-linux-gnu/8/include
/usr/local/include
/usr/lib/gcc/x86_64-linux-gnu/8/include-fixed
/usr/include/x86_64-linux-gnu
/usr/include
End of search list.
是否有一种方便的方法让Make向我展示它正在检查标题的位置?
Make不知道编译过程及其涉及的概念:它不知道在其工作过程中检查标题。在执行makefile时,可能会运行调用GCC前端执行编译的命令,然后它将尝试以已经概述的方式定位头文件。
在其他条件相同的情况下,代码编译应该在某些Fedora系统上成功但在某些CentOS系统上失败的最有可能的原因是因为#include <google/protobuf/someheader.h>
无法解决,是一些具有root权限的用户安装了开发包protobuf-devel
或者在Fedora系统上使用protobuf
来源tarball并且没有人在CentOS系统上做过同样的事情。
如果确实已经在两个系统上正确安装了protobuf
,那么其他方面并不相同。
google/protobuf/someheader.h
可能是由protobuf
的(较新的?)版本提供的标题,它安装在Fedora系统上,但不是由安装在CentOS系统上的(较旧的?)版本提供的。
其他一些不平等可能会解释您的情况,但如果没有Fedora和CentOS软件包安装步骤的具体细节以及后续和失败构建的具体示例,则只能推测性地描述所有这些步骤。几乎可以肯定的是,你现在还不知道GCC解决#include
指令的方法。
类似的注意事项适用于您在zeromq
头文件中找到的编译失败。