2个Dirs,3个头文件的makefile错误
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2个Dirs,3个头文件的makefile错误相关的知识,希望对你有一定的参考价值。
我有2个Dirs和3个头文件存储在其中,如下所示:
目录A:包含头文件A和C目录B:包含头文件B.
A和B是名为Apps的目录的子目录(这是其他一些目录的子目录)。
基本上,问题发生在类似的情况,我从中解决了问题。因此,下面显示的C ++源文件是微不足道的:
头文件A.h:
#ifndef A_H
#define A_H
class A
{
};
#endif /// A_H
头文件C.h:
#ifndef C_H
#define C_H
#include "B.h"
class C
{
};
A.h的测试员,即。 TestA.cpp:
/** TestA.cpp */
#include "A.h"
/// ...
int main()
{
}
测试C.h,即。 TestC.cpp:
/** TestC.cpp */
#include "C.h"
/// ...
int main()
{
}
Dir B包含1个C ++头文件B.h及其测试器TestB.cpp,两者都很简单:
头文件B.h:
#ifndef B_H
#define B_H
#include "A.h"
class B
{
};
#endif /// B_H
测试B.h,即。 TestB.cpp:
/** TestB.cpp */
#include "B.h"
/// ...
int main()
{
}
3个测试者TestA.cpp,TestB.cpp和TestC.cpp分别有3个makefile:MakeA,MakeB和MakeC。正如预期的那样,MakeA和MakeC在dir A中,MakeB在dir B中。
我没有显示MakeA和MakeB,因为它们正常工作。
MakeC中发生错误:
CPP = g++
OFLAG = -o
CFLAG = -std=c++11 -c
PROG1 = TestC
HC = C
HB = B
HA = A
HBDIR = ../B/
HADIR = ./
IHBDIR = -I$(HBDIR)
IHADIR = -I$(HADIR)
all : $(PROG1).o $(PROG1).exe run1
$(PROG1).o : $(PROG1).cpp $(HADIR)$(HC).h $(HBDIR)$(HB).h $(HADIR)$(HA).h
$(CPP) $(CFLAG) $(IHADIR) $(IHBDIR) $<
$(PROG1).exe : $(PROG1).o
$(CPP) $(OFLAG) $@ $^
run1:
$(PROG1)
此make文件无法找到头文件A(头文件B包含#)并给出以下错误:
In file ...
../B/B.h fatal error: A.h : no such file or directory
#include "A.h"
compilation terminated
显然,make正在B.h的目录中寻找A.h(因为B.h #includes A.h)。但是,我已经定义了符号HADIR(as ./),它应该导致make在默认目录中搜索,即Dir A.
请注意:
1)头文件引用是简单和线性的:A.h是B.h的#included,包括C.h的#include。
2)我不希望在源文件中硬编码dir路径。它们必须只存储在makefile中,因为这是makefile的目的之一。
3)我知道的问题有两个解决方案:a)将C.h,它的测试器和makefile重新定位到目录C.但是,我不想这样做,因为A.h和C.h在语义上是相关的。 b)在MakeC中,将HADIR定义为../A,而不是./但我不明白为什么我应该这样做。
使用MakeC作为输入makefile调用make实用程序的BAT文件如下:
cd /f/Files/C/SW/Applications/Samples/C++Samples/Introductory/
Classes/Apps/A/
make -f MakeC
谢谢。
有关哪些路径包含搜索的信息,请参阅this link。假设您使用的形式为include "file"
(带引号,而不是#include <file>
,稍有不同):
默认情况下,预处理器首先查找指令#include“file”的引用形式所包含的头文件,该文件首先是相对于当前文件的目录,然后是预先配置的标准系统目录列表。例如,如果/usr/include/sys/stat.h包含#include“types.h”,GCC首先在/ usr / include / sys中查找types.h,然后在其通常的搜索路径中查找。
...
您可以使用许多命令行选项将其他目录添加到搜索路径。最常用的选项是-Idir,它会导致在当前目录(对于指令的引用形式)之后和标准系统目录之前搜索dir。您可以在命令行上指定多个-I选项,在这种情况下,将按从左到右的顺序搜索目录。
注意到
当前文件的目录
指的是从中调用gcc的目录,而不是源文件的目录(不是最好的措辞)。因此,如果从.c文件的目录中调用gcc,则需要在编译器选项中添加-IA -IB
标志,然后不要在#include
指令中包含路径(假设从目录中调用gcc)。 c文件)。
如果确实要包含路径,则它们必须相对于调用gcc的目录,或者其中一个包含-I
选项指定的路径。
----编辑-----
好的,我刚看了你的更新,似乎TestC.c在目录A中,我没有从你的原始帖子中获得这意味着你正在从目录A编译。在这种情况下我无法重现你的问题(在至少不在我的Linux系统上):
[157]~/tmp/tmp9/A> find .. -type f -exec echo "------ " {} " ------" ; -exec more {} ;
------ ../A/A.h ------
#pragma message "A.h"
// blank
------ ../A/C.h ------
#pragma message "C.h"
#include "B.h"
------ ../A/testC.c ------
#pragma "message file.c"
#include "C.h"
int main() {}
------ ../B/B.h ------
#pragma message B.H
#include "A.h"
[157]~/tmp/tmp9/A> gcc -I. -I../B testC.c
In file included from testC.c:2:
C.h:1: note: #pragma message: C.h
In file included from C.h:2,
from testC.c:2:
../B/B.h:1: warning: expected a string after ‘#pragma message’
In file included from ../B/B.h:2,
from C.h:2,
from testC.c:2:
./A.h:1: note: #pragma message: A.h
[157]~/tmp/tmp9/A>
make命令应该回显用于构建测试程序的命令 - 将该输出附加到问题中。
对于https://gcc.gnu.org/onlinedocs/gcc-3.0.2/cpp_2.html#SEC6:
第2.1节:包含语法
[#include with quotation marks]用于您自己程序的头文件。它首先在包含当前文件的目录中搜索名为file的文件,然后在用于<file>的相同目录中搜索
由于我们正在讨论另一个标题中的include-with-quotes,我们必须弄清楚什么是“当前文件”。我们的选择是:
- 包含原始标头的源文件
- 原始标题本身(现在包括主题标题)
第2.2节:包括操作
`#include'指令通过指示C预处理器将指定文件作为输入进行扫描,然后继续使用当前文件的其余部分
对我来说,这个措辞意味着#include
充当“当前文件”处理的中断,在此期间包含的文件变为“当前”。 (考虑如果将#include
解释为扩展到#including
文件或作为#include
文件的一部分,将如何编写。)此外,如果#include "A.h"
的引号版本在#including文件的上下文中被解释,它将会破坏一直都是无用的。
所以B.h
内的A.h
相对于B.h
的位置寻找$HADIR
。但$HBDIR
不等于-I
所以这次查找失败了。
但请注意,#include
添加到应该由#include
-with-angle-bracket搜索的位置列表...也应该在“当前文件的目录”之后搜索Prog
-with-quotation-marks ... so你的编译器正在用它的搜索做一些奇怪的事情。
我也确认gcc 4.8.5不会重现您的问题。这是我相对于目录[Prog]$ find ..
../Prog
../Prog/A.h
../Prog/MakeC
../Prog/TestA.cpp
../Prog/TestC.cpp
../Prog/C.h
../B
../B/B.h
../B/TestB.cpp
的测试设置
[Prog]$ make -f MakeC
g++ -std=c++11 -c -I./ -I../B/ TestC.cpp
g++ -o TestC.exe TestC.o
TestC
然后建立产量:
#include
你用的是什么编译器? (我敢打赌它是旧的(大约gcc 2.9.6),或者由供应商定制以定位嵌入式平台)我看到有趣的包括路径检查其中一些。
这是一个小型的设计演示,用于显示#pragma once
#include "b.h"
-with-quotes的正确行为:
INC / A.H
#pragma once
extern int garbage;
INC / b.h
#include "inc/a.h"
test.c的
$ gcc -E test.c
# 1 "test.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "test.c"
# 1 "inc/a.h" 1
# 1 "inc/b.h" 1
extern int garbage;
# 4 "inc/a.h" 2
# 1 "test.c" 2
然后
.c
请注意,主要的"inc/a.h"
文件直接包含"b.h"
,并且编译器命令行上没有给出搜索路径,但它仍然找到cd /f/Files/C/SW/Applications/Samples/C++Samples/Introductory/Classes/Apps/
make -f A/MakeC
。
好的,我终于解决了以下问题:
1)使BAT文件将默认目录设置为A和B目录之上的1 dir,即应用程序目录,并从那里调用make实用程序:
CPP = g++
OFLAG = -o
CFLAG = -std=c++11 -c
# BAT file invoking MakeC sets default to ... Classes/Apps/
HADIR = ./A/
HBDIR = ./B/
# HADIR contains HA and HC
# HBDIR contains HB
HA = A
HC = C
HB = B
PROG1 = TestC
IHADIR = -I$(HADIR)
IHBDIR = -I$(HBDIR)
all : $(PROG1).o $(PROG1).exe run1
$(PROG1).o : $(HADIR)$(PROG1).cpp $(HADIR)$(HC).h $(HBDIR)$(HB).h $(HADIR)$(HA).h
# Create obj file in HADIR explicitly
$(CPP) $(OFLAG) $(HADIR)$@ $(CFLAG) $(IHADIR) $(IHBDIR) $<
$(PROG1).exe : $(HADIR)$(PROG1).o
# Create exe file in HADIR explicitly
$(CPP) $(OFLAG) $(HADIR)$@ $^
clean:
# Specify dir explicitly
rm $(HADIR)*.exe $(HADIR)*.o
run1:
# Specify dir explicitly
$(HADIR)$(PROG1)
2)修改makefile以从存储它的dir中显式访问每个头,在指定的dir中创建obj和exe文件并在指定的dir中调用exe文件:
#include "(Adir)/A.h"
正如我所说,我正在使用g ++ 4.8.1。
对我有用的是,让调用BAT文件将默认目录设置为高于包含源文件的目录的一个级别,并在makefile中明确指定目录。
----编辑---- 我想提出一个可能的原因,为什么这个工作。
首先,请注意,最初,HADIR变量设置为./(默认目录)。
正如@ lockcmpxchg8b所说,“默认目录”可以解释为(a)原始文件或(b)#included头文件。这是唯一的两种可能性。由于编译器找不到#included标头,这意味着它选择了错误的可能性。这显然是特定于版本的gcc问题,因为其他人无法在以后的gcc版本上重现问题。
然后,解决方案是避免使用./作为诸如HADIR之类的dir符号的值。而是将make外部的默认目录设置为另一个目录。在这种情况下,它是在A和B之上的一个级别(即应用程序)完成的。然后,makefile的dir符号可以与该dir完全相同,显然不会是./
对于除./之外的值(由编译器解释为默认目录),编译器会根据需要解释dir符号的值。
我想在你的“B.h”中,你应该这样做:#include "../A/A.h"
似乎“A.h”位于“B.h”目录的相邻目录中。所以当“B.h”试图在当前目录中查找它时,它找不到它。我猜qazxswpoi
以上是关于2个Dirs,3个头文件的makefile错误的主要内容,如果未能解决你的问题,请参考以下文章