opcja gcc / g++ do umieszczenia wszystkich plików obiektowych w osobnym katalogu

Zastanawiam się, dlaczego gcc / g++ nie ma opcji umieszczania wygenerowanych plików obiektowych w określonym katalogu.

Na przykład:

mkdir builddir
mkdir builddir/objdir
cd srcdir

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

Wiem, że możliwe jest osiągnięcie tego z opcjami oddzielnymi-o podanymi kompilatorowi, np.:

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

... i Wiem, że mogę pisać pliki Makefile poprzez dyrektywy VPATH i vpath, aby to uprościć.

Ale to dużo pracy w złożonym środowisku budowania.

I could also użycie

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

Ale kiedy używam tego podejścia mój srcdir jest pełen .o śmieci później.

Myślę więc, że opcja z semantyką --outdir byłaby bardzo przydatna.

Jaka jest twoja opinia?

EDIT: nasze pliki Makefile są napisane w taki sposób, że .o pliki faktycznie umieszczone w builddir / obj. Ale zastanawiam się, czy nie ma lepszego podejścia.

EDIT: istnieje kilka podejść, które nakładają ciężar na osiągnięcie pożądane zachowanie do systemu budowania (Aka Make, CMake itp.). Ale uważam je wszystkie za obejścia ze względu na słabość gcc (i innych kompilatorów też).

 66
Author: R Samuel Klatchko, 2009-11-29

10 answers

To jest ścięty plik makefile dla jednego z moich projektów, który kompiluje źródła w 'src' i umieszcza .o pliki w katalogu "obj". Kluczowym bitem jest użycie funkcji patsubst () - zobacz instrukcję GNU make (która jest właściwie całkiem dobrą lekturą) po szczegóły:

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)
 76
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-16 19:44:07

Może zmienimy katalog i uruchomimy kompilację stamtąd:

cd builddir/objdir
gcc ../../srcdir/file1.c ../../srcdir/file2.c ../../srcdir/file3.c
To wszystko. gcc zinterpretuje includes formularza #include "path/to/header.h" jako zaczynające się w katalogu, w którym istnieje plik, więc nie musisz niczego modyfikować.
 20
Author: R Samuel Klatchko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-17 01:33:09

Banalnym, ale skutecznym obejściem jest dodanie następującego rozwiązania zaraz po wywołaniu gcc w pliku Makefile:

mv *.o ../builddir/objdir

Lub nawet soft-clean (ewentualnie rekurencyjny) po zakończeniu kompilacji, jak

rm -f *.o

Lub

find . -name \*.o -exec rm {} \;
 16
Author: Davide,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-12 07:44:48

Możesz użyć prostego wrappera wokół gcc, który wygeneruje niezbędne opcje -o i wywoła 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

Oto taki gcc_wrap skrypt w najprostszej formie:

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

Oczywiście standardowym sposobem jest rozwiązanie problemu z Makefiles, lub prostszym, z CMake lub bakefile, ale prosiłeś o rozwiązanie, które dodaje funkcjonalność do gcc, I myślę, że jedynym sposobem jest napisanie takiego wrappera. Oczywiście, możesz również łatać źródła gcc, aby zawierały nowa opcja, ale to może być trudne.

 11
Author: Frank,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-16 20:05:53

Wydaje mi się, że masz pomysł na odwrót...?!

Idea Makefiles polega na tym, że przetwarzają tylko pliki, które zostały zaktualizowane od ostatniej kompilacji, aby skrócić czas (ponownego)kompilacji. Jeśli połączysz wiele plików w jednym uruchomieniu kompilatora, w zasadzie pokonasz ten cel.

Twój przykład:

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

Nie podałeś reguły 'make', która pasuje do tej linii poleceń; ale jeśli jakikolwiek z tych trzech plików został zaktualizowany, musisz uruchomić tę linię, i przekompilować wszystkie trzy pliki, które mogą nie być wcale konieczne. Utrzymuje on również 'make' od wywoływania oddzielnego procesu kompilacji dla każdego pliku źródłowego, tak jak robi to w przypadku oddzielnej kompilacji(przy użyciu opcji '- j', jak zdecydowanie sugerowałbym).

Napisałem Makefile tutorial gdzie indziej, który zawiera dodatkowe szczegóły (takie jak automatyczne wykrywanie plików źródłowych zamiast ich kodowania na twardo w pliku Makefile, automatyczne określanie zależności między nimi i inline testing).

Wszystko, co musisz zrobić, aby uzyskać oddzielny katalog obiektów, to dodać odpowiednie informacje o katalogu do linii OBJFILES := i reguły %.o: %.c Makefile z tego samouczka. Odpowiedź Neila Butterwortha ma ładny przykład, jak dodać informacje o katalogu.

(Jeśli chcesz używać DEPFILES lub TESTFILES, jak opisano w samouczku, musisz dostosować linie DEPFILES := i TSTFILES := oraz regułę %.t: %.c Makefile pdclib.a .)

 7
Author: DevSolar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-15 09:05:18

W międzyczasie znalazłem rozwiązanie "w połowie drogi", używając opcji-combine.

Przykład:

mkdir builddir
mkdir builddir/objdir
cd srcdir

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

To "łączy" wszystkie pliki źródłowe w jeden plik obiektowy.

Jest to jednak nadal "w połowie drogi", ponieważ musi przekompilować wszystko, gdy zmieni się tylko jeden plik źródłowy.

 3
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-12 09:52:56

Myślę, że telling pass gcc nie ma osobnej opcji, aby powiedzieć, gdzie umieścić plik obiektowy, ponieważ już go ma. To "- c " - mówi w jakim katalogu umieścić obiekt.

Posiadanie dodatkowej flagi tylko dla katalogu musi zmienić meening "- c". Na przykład:

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

Nie można umieścić pliku /a/b/c/.o Pod /a1/a2 / A3, ponieważ obie ścieżki są bezwzględne. Tak więc "- c " należy zmienić tylko na nazwę pliku obiektowego.

Radzę rozważyć zastąpienie makefile, jak cmake, scons i inne. Pozwoli to na wdrożenie systemu budowania zarówno dla prostego projektu, jak i dla większego.

Zobacz na przykład, jak łatwo jest skompilować za pomocą cmake your example. Wystarczy utworzyć plik CMakeList.txt w srcdir/:

cmake_minimum_required(VERSION 2.6)
project(test) 

add_library(test file1.c file2c file3.c) 

A teraz wpisz:

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

To wszystko, pliki obiektowe będą znajdować się gdzieś pod builddir / objdir.

Osobiście używam cmake i uważam, że jest bardzo wygodny. Automatycznie generuje zależności i ma inne smakołyki.
 2
Author: dimba,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-11 09:50:54

Próbuję rozgryźć to samo. Dla mnie to działało

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
``
 2
Author: Venkatesh Jatla,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-03-11 02:50:15

Jest to jeden z problemów autoconf rozwiązuje.

Jeśli kiedykolwiek robiłeś ./configure && make wiesz, czym jest autoconf: to narzędzie generuje te ładne skrypty konfiguracyjne. Nie wszyscy wiedzą, że zamiast tego możesz zrobić mkdir mybuild && cd mybuild && ../configure && make i to magicznie zadziała, ponieważ autoconf jest świetny w ten sposób.

Skrypt configure generuje pliki Makefile w katalogu build . Wtedy cały proces budowania dzieje się tam. Więc wszystkie pliki build naturalnie pojawiają się tam, a nie w źródło.

Jeśli masz pliki źródłowe wykonujące #include "../banana/peel.h" i nie możesz ich zmienić, to trudno jest to naprawić (musisz skopiować lub połączyć symbolicznie wszystkie pliki nagłówkowe do katalogu kompilacji). Jeśli możesz zmienić pliki źródłowe na #include "libfood/comedy/banana/peel.h" zamiast tego, to wszystko jest ustawione.

Autoconf nie jest dokładnie łatwy, szczególnie w przypadku dużych istniejących projektów. Ale ma swoje zalety.

 1
Author: Jason Orendorff,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-16 19:37:39

Osobiście dla pojedynczych plików robię to,

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

Folder Temps zachowa wszystkie pliki obiektu, wstępnie przetworzone I złożenia.

Jest to prymitywny sposób robienia rzeczy i wolałbym powyżej odpowiedzi za pomocą Plików Makefiles.

 0
Author: nikhil chaubey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-08-25 07:47:25