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,我们必须弄清楚什么是“当前文件”。我们的选择是:

  1. 包含原始标头的源文件
  2. 原始标题本身(现在包括主题标题)

第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错误的主要内容,如果未能解决你的问题,请参考以下文章

Makefile 错误:找不到命令 - 创建共享库时

第三部分Makefile介绍

Linux开发-makefile

Makefile详解

Makefile文件

Makefile - 从多个目录构建