IT박스

모든 오브젝트 파일을 별도의 디렉토리에 배치하는 gcc / g ++ 옵션

itboxs 2020. 12. 4. 08:02
반응형

모든 오브젝트 파일을 별도의 디렉토리에 배치하는 gcc / g ++ 옵션


gcc / 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

... 그리고 이것을 단순화하기 위해 VPATH 및 vpath 지시문을 통해 Makefile을 작성할 수 있다는 것을 알고 있습니다.

그러나 이것은 복잡한 빌드 환경에서 많은 작업입니다.

나는 또한 사용할 수 있습니다

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

하지만이 방법을 사용하면 srcdir은 나중에 .o 쓰레기로 가득 차 있습니다.

따라서 --outdir의 의미를 가진 옵션이 매우 유용 할 것이라고 생각합니다.

당신의 의견 것입니다?

편집 : 우리의 Makefile은 .o 파일이 실제로 builddir / obj에 배치되는 방식으로 작성됩니다. 하지만 더 나은 접근 방법이 있을지 궁금합니다.

편집 : 빌드 시스템 (일명 Make, CMake 등)에 원하는 동작을 달성하는 데 부담을주는 몇 가지 접근 방식이 있습니다. 그러나 나는 그것들을 모두 gcc (그리고 다른 컴파일러도)의 약점에 대한 해결 방법 이라고 생각합니다 .


이것은 'src'에 소스를 컴파일하고 "obj"디렉토리에 .o 파일을 배치하는 내 프로젝트 중 하나에 대한 잘려진 makefile입니다. 핵심 부분은 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

그게 다야. gcc는 형식의 포함을 #include "path/to/header.h"파일이 존재하는 디렉토리에서 시작 하는 것으로 해석 하므로 아무것도 수정할 필요가 없습니다.


사소하지만 효과적인 해결 방법은 Makefile에서 gcc 호출 직후에 다음을 추가하는 것입니다.

mv *.o ../builddir/objdir

또는 컴파일이 완료된 후 소프트 클린 (재귀적일 수 있음)도 마찬가지입니다.

rm -f *.o

또는

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

gcc필요한 -o옵션 을 생성 하고 다음을 호출 하는 간단한 래퍼를 사용할 수 있습니다 gcc.

$ ./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

다음은 gcc_wrap가장 간단한 형태 스크립트입니다.

#!/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: $!");
}

물론, 표준 방법으로 문제를 해결하는 것입니다 Makefiles, 또는 간단한과 CMakebakefile,하지만 당신은 특별히에 기능을 추가하는 솔루션을 요구 gcc하고, 나는 유일한 방법은 래퍼를 작성하는 것입니다 생각합니다. 물론 gcc새로운 옵션을 포함하도록 소스를 패치 할 수도 있지만 어려울 수 있습니다.


개념을 거꾸로 잡았다 고 생각합니다 ...?!

The idea behind Makefiles is that they only process the files that have been updated since the last build, to cut down on (re-)compilation times. If you bunch multiple files together in one compiler run, you basically defeat that purpose.

Your example:

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

You didn't give the 'make' rule that goes with this command line; but if any of the three files has been updated, you have to run this line, and recompile all three files, which might not be necessary at all. It also keeps 'make' from spawning a seperate compilation process for each source file, as it would do for seperate compilation (when using the '-j' option, as I would strongly suggest).

I wrote a Makefile tutorial elsewhere, which goes into some extra detail (such as auto-detecting your source files instead of having them hard-coded in the Makefile, auto-determining include dependencies, and inline testing).

All you would have to do to get your seperate object directory would be to add the appropriate directory information to the OBJFILES := line and the %.o: %.c Makefile rule from that tutorial. Neil Butterworth's answer has a nice example of how to add the directory information.

(If you want to use DEPFILES or TESTFILES as described in the tutorial, you'd have to adapt the DEPFILES := and TSTFILES := lines plus the %.t: %.c Makefile pdclib.a rule, too.)


I think that telling pass gcc doesn't have an separate option to say where to put object file, since it already has it. It's "-c" - it says in what directory to put object.

Having additional flag for directory only must change meening of "-c". For example:

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

You can not put /a/b/c/file.o under /a1/a2/a3, since both paths are absolute. Thus "-c" should be changed to name object file only.

I advise you to consider a replacement of makefile, like cmake, scons and other. This will enable to implement build system as for for simple project as well as for bigger one too.

See for example how it's easy to compile using cmake your example. Just create file CMakeList.txt in srcdir/:

cmake_minimum_required(VERSION 2.6)
project(test) 

add_library(test file1.c file2c file3.c) 

And now type:

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

That's all, object files will reside somewhere under builddir/objdir.

I personaly use cmake and find it very convinient. It automatically generates dependencies and has other goodies.


Meanwhile I found a "half-way" solution by using the -combine option.

Example:

mkdir builddir
mkdir builddir/objdir
cd srcdir

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

this "combines" all source files into one single object file.

However, this is still "half-way" because it needs to recompile everything when only one source file changes.


This is among the problems autoconf solves.

If you've ever done ./configure && make you know what autoconf is: it's the tool that generates those nice configure scripts. What not everyone knows is that you can instead do mkdir mybuild && cd mybuild && ../configure && make and that will magically work, because autoconf is awesome that way.

The configure script generates Makefiles in the build directory. Then the entire build process happens there. So all the build files naturally appear there, not in the source tree.

If you have source files doing #include "../banana/peel.h" and you can't change them, then it's a pain to make this work right (you have to copy or symlink all the header files into the build directory). If you can change the source files to say #include "libfood/comedy/banana/peel.h" instead, then you're all set.

autoconf is not exactly easy, especially for a large existing project. But it has its advantages.


I am trying to figure out the same thing. For me this worked

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
``

Personally for single files I do this,

rm -rf temps; mkdir temps; cd temps/ ; gcc -Wall -v --save-temps  ../thisfile.c ; cd ../ ; geany thisfile.c temps/thisfile.s temps/thisfile.i

temps folder will keep all the object, preprocessed and assembly files.

This is a crude way of doing things and I would prefer above answers using Makefiles.

참고URL : https://stackoverflow.com/questions/1814270/gcc-g-option-to-place-all-object-files-into-separate-directory

반응형