代码之家  ›  专栏  ›  技术社区  ›  devin

使用不同目录中的源文件生成文件

  •  118
  • devin  · 技术社区  · 16 年前

    我有一个项目,目录结构如下:

                             $projectroot
                                  |
                  +---------------+----------------+
                  |               |                |
                part1/          part2/           part3/
                  |               |                |
           +------+-----+     +---+----+       +---+-----+
           |      |     |     |        |       |         |
         data/   src/  inc/  src/     inc/   src/       inc/
    

    我应该如何编写一个在部分/ SRC(或者在任何地方)可以在C/C++源文件中部分地链接/链接的Mag文件?/SRC?

    我能做点什么吗 -i$projectroot/part1/src-i$projectroot/part1/inc-i$projectroot/part2/src…

    如果这可行,有没有更简单的方法可以做到。我见过在每个对应部分都有makefile的项目?文件夹。[在这篇文章中,我使用了bash语法中的问号]

    9 回复  |  直到 8 年前
        1
  •  93
  •   akhan    8 年前

    传统的方法是 Makefile 在每个子目录中( part1 , part2 等)允许您独立构建它们。此外,有一个 生成文件 在构建所有内容的项目的根目录中。“根” 生成文件 将类似于以下内容:

    all:
        +$(MAKE) -C part1
        +$(MAKE) -C part2
        +$(MAKE) -C part3
    

    由于make目标中的每一行都在其自己的shell中运行,因此无需担心遍历回目录树或其他目录。

    我建议你看看 GNU make manual section 5.7 很有帮助。

        2
  •  83
  •   Alex44    9 年前

    如果一个子目录中的代码依赖于另一个子目录中的代码,那么最好在顶层使用一个makefile。

    Recursive Make Considered Harmful 为了充分的理由,但基本上你想要make有完整的信息,它需要决定一个文件是否需要重建,如果你只告诉它你项目的三分之一,它就不会有这个信息。

    上面的链接似乎无法连接到。此处可访问同一文档:

        3
  •  29
  •   CodeGoat    16 年前

    vpath选项可能会派上用场,它告诉make在哪些目录中查找源代码。不过,对于每个include路径,您仍然需要-i选项。一个例子:

    CXXFLAGS=-Ipart1/inc -Ipart2/inc -Ipart3/inc
    VPATH=part1/src:part2/src:part3/src
    
    OutputExecutable: part1api.o part2api.o part3api.o
    

    这将自动在任何vpath指定的目录中找到匹配的partxapi.cpp文件并编译它们。但是,当您的SRC目录被分解为子目录时,这更有用。正如其他人所说,对于您所描述的,您最好为每个部分准备一个makefile,尤其是当每个部分都可以独立时。

        4
  •  23
  •   RC.    16 年前

    您可以向根makefile添加规则,以便在其他目录中编译必要的cpp文件。下面的makefile示例应该是一个很好的开始,可以让您到达您想去的地方。

    CC=g++
    TARGET=cppTest
    OTHERDIR=../../someotherpath/in/project/src
    
    SOURCE = cppTest.cpp
    SOURCE = $(OTHERDIR)/file.cpp
    
    ## End sources definition
    INCLUDE = -I./ $(AN_INCLUDE_DIR)  
    INCLUDE = -I.$(OTHERDIR)/../inc
    ## end more includes
    
    VPATH=$(OTHERDIR)
    OBJ=$(join $(addsuffix ../obj/, $(dir $(SOURCE))), $(notdir $(SOURCE:.cpp=.o))) 
    
    ## Fix dependency destination to be ../.dep relative to the src dir
    DEPENDS=$(join $(addsuffix ../.dep/, $(dir $(SOURCE))), $(notdir $(SOURCE:.cpp=.d)))
    
    ## Default rule executed
    all: $(TARGET)
            @true
    
    ## Clean Rule
    clean:
            @-rm -f $(TARGET) $(OBJ) $(DEPENDS)
    
    
    ## Rule for making the actual target
    $(TARGET): $(OBJ)
            @echo "============="
            @echo "Linking the target $@"
            @echo "============="
            @$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
            @echo -- Link finished --
    
    ## Generic compilation rule
    %.o : %.cpp
            @mkdir -p $(dir $@)
            @echo "============="
            @echo "Compiling $<"
            @$(CC) $(CFLAGS) -c $< -o $@
    
    
    ## Rules for object files from cpp files
    ## Object file for each file is put in obj directory
    ## one level up from the actual source directory.
    ../obj/%.o : %.cpp
            @mkdir -p $(dir $@)
            @echo "============="
            @echo "Compiling $<"
            @$(CC) $(CFLAGS) -c $< -o $@
    
    # Rule for "other directory"  You will need one per "other" dir
    $(OTHERDIR)/../obj/%.o : %.cpp
            @mkdir -p $(dir $@)
            @echo "============="
            @echo "Compiling $<"
            @$(CC) $(CFLAGS) -c $< -o $@
    
    ## Make dependancy rules
    ../.dep/%.d: %.cpp
            @mkdir -p $(dir $@)
            @echo "============="
            @echo Building dependencies file for $*.o
            @$(SHELL) -ec '$(CC) -M $(CFLAGS) $< | sed "s^$*.o^../obj/$*.o^" > $@'
    
    ## Dependency rule for "other" directory
    $(OTHERDIR)/../.dep/%.d: %.cpp
            @mkdir -p $(dir $@)
            @echo "============="
            @echo Building dependencies file for $*.o
            @$(SHELL) -ec '$(CC) -M $(CFLAGS) $< | sed "s^$*.o^$(OTHERDIR)/../obj/$*.o^" > $@'
    
    ## Include the dependency files
    -include $(DEPENDS)
    
    
        5
  •  18
  •   dashesy    13 年前

    如果源文件分布在多个文件夹中,并且有单独的生成文件是有意义的,那么正如前面建议的那样,递归生成是一种很好的方法,但是对于较小的项目,我发现在 生成文件 与他们的相对路径 生成文件 这样地:

    # common sources
    COMMON_SRC := ./main.cpp \
                  ../src1/somefile.cpp \
                  ../src1/somefile2.cpp \
                  ../src2/somefile3.cpp \
    

    然后我可以设置 VPATH 这种方式:

    VPATH := ../src1:../src2
    

    然后我构建对象:

    COMMON_OBJS := $(patsubst %.cpp, $(ObjDir)/%$(ARCH)$(DEBUG).o, $(notdir $(COMMON_SRC)))
    

    现在规则很简单:

    # the "common" object files
    $(ObjDir)/%$(ARCH)$(DEBUG).o : %.cpp Makefile
        @echo creating $@ ...
        $(CXX) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
    

    而构建输出更容易:

    # This will make the cbsdk shared library
    $(BinDir)/$(OUTPUTBIN): $(COMMON_OBJS)
        @echo building output ...
        $(CXX) -o $(BinDir)/$(OUTPUTBIN) $(COMMON_OBJS) $(LFLAGS)
    

    一个人甚至可以 VPATH 自动生成:

    VPATH := $(dir $(COMMON_SRC))
    

    或者利用这个事实 sort 删除重复项(尽管不重要):

    VPATH := $(sort  $(dir $(COMMON_SRC)))
    
        6
  •  9
  •   IlDan    12 年前

    我认为最好指出使用make(递归或非递归)通常是您可能想要避免的,因为与今天的工具相比,它很难学习、维护和扩展。

    这是一个很好的工具,但是它的直接使用应该在2010年被认为是过时的。

    当然,除非你在一个特殊的环境中工作,例如,在一个遗留项目中工作。

    使用IDE, CMake 或者,如果你很坚强, Autotools .

    (因投反对票而编辑,Ty Honza指出)

        7
  •  2
  •   jvriesem    13 年前

    RC的职位非常有用。我从来没有想过使用$(dir$@)函数,但它确实做到了我需要它做的事情。

    在parentdir中,有一组包含源文件的目录:dira、dirb、dirc。各种文件依赖于其他目录中的对象文件,因此我希望能够从一个目录中生成一个文件,并通过调用与该依赖项关联的make file使其成为依赖项。

    从本质上讲,我在parentdir中创建了一个makefile,它有一个(除其他外)类似于rc的一般规则:

    %.o : %.cpp
            @mkdir -p $(dir $@)
            @echo "============="
            @echo "Compiling $<"
            @$(CC) $(CFLAGS) -c $< -o $@
    

    为了继承这个通用规则,每个子目录都包含这个上层makefile。在每个子目录的makefile中,我为每个文件编写了一个自定义规则,以便跟踪每个单独文件所依赖的所有内容。

    每当我需要生成一个文件时,我(本质上)使用这个规则递归地生成任何/所有依赖项。很完美!

    注意:有一个名为“makepp”的实用程序,它似乎更直观地完成了这项任务,但为了便于携带,而不是依赖于其他工具,我选择了这样做。

    希望这有帮助!

        8
  •  2
  •   EhevuTov    13 年前

    Recursive Use of Make

    all:
        +$(MAKE) -C part1
        +$(MAKE) -C part2
        +$(MAKE) -C part3
    

    这允许 make 拆分为作业并使用多个核心

        9
  •  0
  •   Baby Groot Duleendra    11 年前

    我建议使用 autotools :

    //## 将生成的对象文件(.o)放入与其源文件相同的目录中,以避免在使用非递归make时发生冲突。

    AUTOMAKE_OPTIONS = subdir-objects
    

    把它包括进去 Makefile.am 其他非常简单的东西。

    这里是 tutorial .