Gcc / g ++ to put all object files in a separate directory

I am wondering why gcc / g ++ is not able to put the generated object files in the specified directory.

For example:

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

I know that this can be achieved with separate -o options given to the compiler, for example:

 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 

... and I know that I can write Makefiles through the VPATH and vpath directives to simplify this.

But this is a lot of work in a complex build environment.

I could also use

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

But when I use this approach, my srcdir is full of .o garbage afterwards.

So, I think the option with the -outdir semantics will be very useful.

What is your opinion?

EDIT : our Make files are written so that the .o files are actually placed in builddir / obj. But I'm just wondering if there could be a better approach.

EDIT . There are several approaches that put a burden on achieving the desired behavior in the build system (as well as Make, CMake, etc.). But I see them as workarounds for the weaknesses of gcc (and other compilers too).

+59
gcc g ++
Nov 29 '09 at 0:37
source share
10 answers

This is a cut-out makefile for one of my projects, which compiles the sources in 'src' and puts the .o files in the "obj" directory. The key bit is to use the patsubst () function - see the GNU manual for more details (this is actually a pretty good read):

 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) 
+68
Dec 12 '09 at 9:58
source share

How about going to the directory and doing the compilation from here:

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

What is it. gcc will interpret, includes the form #include "path/to/header.h" , starting from the directory in which the file is located, so you do not need to change anything.

+18
Nov 29 '09 at 1:22
source share

A trivial but effective workaround is to add the following after a gcc call to the Makefile:

 mv *.o ../builddir/objdir 

or even soft-clean (possibly recursive) after compilation, for example

 rm -f *.o 

or

 find . -name \*.o -exec rm {} \; 
+15
Dec 12 '09 at 7:44
source share

You can use a simple wrapper around gcc that will generate the necessary -o options and call 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 

Here is a gcc_wrap script in its simplest form:

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

Of course, the standard way is to solve the problem with Makefiles or simpler using CMake or bakefile , but you specifically asked for a solution that adds gcc functionality, and I think the only way is to write such a shell. Of course, you can also fix gcc sources to include a new option, but this can be tricky.

+11
Dec 16 '09 at 19:36
source share

I believe that you understood the concept backwards ...?!

The idea behind Makefiles is that they only process files that have been updated since the last build to reduce (re-) compilation time. If you put together several files in one run of the compiler, you basically defeat this goal.

Your example:

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

You did not define the 'make' rule corresponding to this command line; but if any of the three files has been updated, you must run this line and recompile all three files that might not be needed at all. It also does not allow "make" to run a separate compilation process for each source file, as it would for a separate compilation (when using the "-j" option, as I highly recommend).

I wrote a Makefile tutorial elsewhere that has some additional details (such as automatically detecting your source files instead of hard-coding them in the Makefile, automatically detecting inclusion dependencies, and built-in testing).

All you have to do to get the directory of individual objects is to add the appropriate directory information to the line OBJFILES := and the rule %.o: %.c Makefile from this tutorial. Neil Butterworth's answer has a good example of how to add information to a directory.

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

+5
Dec 15 '09 at 9:05
source share

I think that passing pass gcc does not have a separate option to tell where to put the object file, since it already has it. This is the "-c" in which directory the object is placed.

The presence of an additional flag for the directory should only change the value 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 cannot put /a/b/c/file.o under / a1 / a2 / a3 since both paths are absolute. Therefore, "-c" should only be changed for the name of the object file.

I advise you to consider replacing makefiles such as cmake , scons, and others. This will allow you to implement an assembly system for both a simple project and a larger one.

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

 cmake_minimum_required(VERSION 2.6) project(test) add_library(test file1.c file2c file3.c) 

And now enter:

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

That's all, object files will be located somewhere in the builddir / objdir file.

I personally use cmake and find it very convenient. It automatically generates dependencies and has other useful properties.

+2
Dec 11 '09 at 9:50
source share

Meanwhile, I found a halfway solution 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 β€œmerges” all source files into a single object file.

However, this is still halfway, because it needs to recompile everything when only one source file changes.

+2
Dec 12 '09 at 9:52
source share

This is one of the problems autoconf solves.

If you've ever done ./configure && make , you know what autoconf is: it is a tool that generates these beautiful configure scripts. What not everyone knows is that you can do mkdir mybuild && cd mybuild && ../configure && make , and it will work magically because autoconf is just as awesome.

configure script creates makefiles in the build directory. Then the whole assembly process takes place. Thus, all assembly files naturally appear there, and not in the source tree.

If you have the source files making #include "../banana/peel.h" and you cannot change them, then it is a pain to make this work correctly (you need to copy or symbolize all the header files to the assembly directory) . If you can modify the source files to say #include "libfood/comedy/banana/peel.h" , then you are all set.

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

+1
Dec 16 '09 at 19:37
source share

I am trying to understand the same thing. It worked for me

 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 '' 
+1
Mar 11 '19 at 2:50
source share

Personally for individual 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 
AT

The temps folder will store all object files that have been pre-processed and assembled.

This is a tough way to do something, and I would prefer the answers above using Makefiles.

0
Aug 25 '19 at 7:33
source share



All Articles