我想知道为什么海湾合作委员会/g++没有选择地生成对象的文件变成一个指定的目录。

例如:

mkdir builddir
mkdir builddir/objdir
cd srcdir

gcc -c file1.c file2.c file3.c **--outdir=**../builddir/objdir

我知道,它是能够实现这个有独立的-o选择给予的编译器,例如:

gcc -c file1.c -o ../builddir/objdir/file1.o
gcc -c file2.c -o ../builddir/objdir/file2.o
gcc -c file3.c -o ../builddir/objdir/file3.o

...我知道,我可以写Makefile通过VPATH和vpath指示,以简化这一点。

但是,这是一个很大的工作在一个复杂的建立环境。

我还可以使用

gcc -c file1.c file2.c file3.c

但是,当我使用这种方法我srcdir是完整的。o垃圾之后。

因此,我认为一个选项用的语义--属性将是非常有用的。

什么是你的意见吗?

编辑:我们的生成文件都写在这样一种方式。o文件实际上被置于进入builddir/obj。但我只是想知道是否有可能是一个更好的办法。

编辑:有几种办法哪个地方的负担,以实现所期望的行为建立的系统(aka作,CMake等)。但我认为他们所为 解决方法 一个软弱的海湾合作委员会(和其他汇编者太)。

有帮助吗?

解决方案

这是我的一个项目的简化makefile,它编译'src'中的源代码并将.o文件放在目录<!>“obj <!>”中。关键是使用patsubst()函数 - 有关详细信息,请参阅GNU make手册(实际上这是一个非常好的阅读):

OUT = lib/alib.a
CC = g++
ODIR = obj
SDIR = src
INC = -Iinc

_OBJS = a_chsrc.o a_csv.o a_enc.o a_env.o a_except.o \
        a_date.o a_range.o a_opsys.o
OBJS = $(patsubst %,$(ODIR)/%,$(_OBJS))


$(ODIR)/%.o: $(SDIR)/%.cpp 
    $(CC) -c $(INC) -o $@ $< $(CFLAGS) 

$(OUT): $(OBJS) 
    ar rvs $(OUT) $^

.PHONY: clean

clean:
    rm -f $(ODIR)/*.o $(OUT)

其他提示

如何改变目录和运行汇编,从有:

cd builddir/objdir
gcc ../../srcdir/file1.c ../../srcdir/file2.c ../../srcdir/file3.c

就是这样。海湾合作委员会的解释包括的形式 #include "path/to/header.h" 作为开始于该目录的文件的存在,所以你不需要修改任何东西。

一个简单而有效的解决方法是在Makefile中的gcc调用之后添加以下内容:

mv *.o ../builddir/objdir
编译完成后,

甚至 soft-clean (可能是递归的),例如

rm -f *.o

find . -name \*.o -exec rm {} \;

您可以使用gcc周围的简单包装器生成必要的-o选项并调用gcc_wrap

$ ./gcc-wrap -c file1.c file2.c file3.c --outdir=obj 
gcc -o obj/file1.o -c file1.c
gcc -o obj/file2.o -c file2.c
gcc -o obj/file3.o -c file3.c

以下是最简单形式的Makefiles脚本:

#!/usr/bin/perl -w

use File::Spec;
use File::Basename;
use Getopt::Long;
Getopt::Long::Configure(pass_through);

my $GCC = "gcc";
my $outdir = ".";
GetOptions("outdir=s" => \$outdir)
    or die("Options error");

my @c_files;
while(-f $ARGV[-1]){
    push @c_files, pop @ARGV;
}
die("No input files") if(scalar @c_files == 0);

foreach my $c_file (reverse @c_files){
    my($filename, $c_path, $suffix) = fileparse($c_file, ".c");
    my $o_file = File::Spec->catfile($outdir, "$filename.o");
    my $cmd = "$GCC -o $o_file @ARGV $c_file";
    print STDERR "$cmd\n";
    system($cmd) == 0 or die("Could not execute $cmd: $!");
}

当然,标准方法是使用CMakebakefile来解决<=>或更简单的问题,但是您明确要求提供一个将功能添加到<=>的解决方案,我认为唯一的方法是编写这样的包装器。当然,您也可以修补<=>来源以包含新选项,但这可能很难。

我相信你倒退了这个概念......?!

Makefile的理念是它们只处理自上次构建以来已更新的文件,以减少(重新)编译时间。如果你在一个编译器运行中将多个文件组合在一起,你基本上就会失败。

你的例子:

gcc -c file1.c file2.c file3.c **--outdir=**../builddir/objdir

您没有给出与此命令行一起使用的'make'规则;但如果三个文件中的任何已更新,则必须运行此行,然后重新编译所有三个文件,这些文件可能根本不需要。它还使'make'不会为每个源文件生成单独的编译过程,就像单独编译一样(当使用'-j'选项时,正如我强烈建议的那样)。

我在别处写了一个 Makefile教程,其中有一些额外的细节(比如自动检测)您的源文件,而不是在Makefile中硬编码,自动确定包括依赖项和内联测试)。

要获得单独的对象目录,您只需要将相应的目录信息添加到OBJFILES :=行和该教程中的%.o: %.c Makefile规则中。 Neil Butterworth的答案有一个很好的例子,说明如何添加目录信息。

(如果你想使用教程中描述的DEPFILES或TESTFILES,你也必须调整DEPFILES :=TSTFILES :=行以及%.t: %.c Makefile pdclib.a 规则。)

我认为告诉传递gcc没有单独的选项来说明放置目标文件的位置,因为它已经拥有它。它是<!>“ - c <!>”; - 它说在放置对象的目录中。

仅为目录添加标记必须更改<!>“-c <!>”的修饰。 例如:

gcc -c file.c -o /a/b/c/file.o --put-object-in-dir-non-existing-option /a1/a2/a3

你不能将/a/b/c/file.o放在/ a1 / a2 / a3下,因为两个路径都是绝对的。因此<!> quot; -c <!> quot;应该更改为仅命名目标文件。

我建议你考虑替换makefile,比如 cmake scons 等。 这样就可以为简单项目以及更大的项目实现构建系统。

例如,查看如何使用cmake编译您的示例。 只需在srcdir /中创建文件CMakeList.txt:

cmake_minimum_required(VERSION 2.6)
project(test) 

add_library(test file1.c file2c file3.c) 

现在输入:

mkdir -p builddir/objdir
cd builddir/objdir
cmake ../../srcdir
make

就是这样,目标文件将驻留在builddir / objdir下的某个地方。

我个人使用cmake并发现它非常方便。它会自动生成依赖关系并有其他好处。

与此同时,我找到了一个<!>“中途<!>”;使用-combine选项解决方案。

示例:

mkdir builddir
mkdir builddir/objdir
cd srcdir

gcc -combine -c file1.c file2.c file3.c -o ../builddir/objdir/all-in-one.o

这个<!>“;结合<!>”;所有源文件都放在一个目标文件中。

然而,这仍然是<!>中途<!>因为当只有一个源文件发生变化时,它需要重新编译所有内容。

这是 autoconf 解决的问题之一。

如果你曾经做过./configure && make,你就知道autoconf是什么:它是生成那些不错的配置脚本的工具。不是每个人都知道的是你可以改为mkdir mybuild && cd mybuild && ../configure && make然后神奇地工作,因为autoconf很棒。

configure脚本在构建目录中生成Makefile 。然后整个构建过程就在那里发生。因此,所有构建文件都自然地出现在那里,而不是在源代码树中。

如果您有源文件正在执行#include "../banana/peel.h"并且您无法更改它们,那么使其正常工作(您必须将所有头文件复制或符号链接到构建目录中)是一件痛苦的事。如果您可以将源文件更改为#include "libfood/comedy/banana/peel.h",那么您已完成设置。

autoconf并非完全 easy ,特别是对于大型现有项目。但它有其优点。

我想弄清楚同样的事情。对我来说,这工作

CC = g++
CFLAGS = -g -Wall -Iinclude
CV4LIBS = `pkg-config --libs opencv4`
CV4FLAGS = `pkg-config --cflags opencv4`

default: track

track:  main.o
    $(CC) -o track $(CV4LIBS) ./obj/main.o

ALLFLAGS = $(CFLAGS) $(CV4FLAGS)
main.o: ./src/main.cpp ./include/main.hpp
    $(CC) $(ALLFLAGS) -c ./src/main.cpp $(CV4LIBS) -o ./obj/main.o
``
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top