LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Software (http://www.linuxquestions.org/questions/linux-software-2/)
-   -   GNU make best practices; single makefile, multiple programs or libs (http://www.linuxquestions.org/questions/linux-software-2/gnu-make-best-practices%3B-single-makefile-multiple-programs-or-libs-947840/)

Enoch247 05-31-2012 03:27 PM

GNU make best practices; single makefile, multiple programs or libs
 
I have a reoccurring problem for which I haven't been able to find a best/common/accepted way of handling when using make with g++. Sometimes in a project I may want to have multiple outputs built from the same sources, but maybe only have a few minor differences(and therefore aren't really separate projects). Make seems really geared towards building only a single program or lib per makefile/project from what I have seen.

An example might be two programs that are built from the same source, but maybe use the code differently (different main func and as a result maybe minor differences in what is included) I know sometimes this is handled by putting all the functionality in a single executable and linking to it with different names (hd/hexdumb, gcc/g++/etc), but sometimes programs are different enough that this is awkward. Another example would be developing a lib and a CLI for the lib together in the same project. They could be separate projects, but keeping them together under a single makefile allows the CLI to be updated whenever the lib's header changes. This allows the libs test scripts to test the updated lib via the newly complied CLI.

It is definitely possible to accomplish this, but it seems like when I do it, I am going against the grain and is usually more difficult. Generally makefiles have one set of linker flags, compiler flags, object list, etc.

Is there a good/accepted way to do this or is doing so a bad practice that I missed somehow? I like sticking to established standards whenever possible.

kakaka 05-31-2012 06:28 PM

Makefile's can descend from the main directory to run other makefile's in sub-directories.
Have you considered the possibility of structuring this as a collection of dependent sub-projects?

merlinblack 05-31-2012 10:45 PM

It depends on how different the programs are, and if some files need to be compiled differently for each, i.e. with different defines for example. If each file is only compile once for everything it's not too hard at all. You would have something like:
(omitting the actual lines that do any work)
Code:

somelib: bla.o bla2.o

cli: somelib cli.o somecommonstuff.o

gui: somelib gui.o somecommonstuff.o

all: cli gui

I have not tried having a file re-compiled for different targets. My guess is you could do something like:
Code:

somecommonstuff_for_cli.o: somecommonstuff.c
    CC CLI_FLAGS -DCLI $< -o somecommontuff_for_cli.o

somecommonstuff_for_gui.o: somecommonstuff.c
    CC GUI_FLAGS -DGUI $< -o somecommontuff_for_gui.o

cli: somelib cli.o somecommonstuff_for_cli.o
.....etc....

This might be Ok for small projects. Otherwise you'll want to split each program out into their own subdirectory, with their own (sub) makefile. The source still be shared amongst them of course, but the intermediate files can go into the subdirectories.

bdt-rob 06-01-2012 02:20 AM

MerlinBlack's approach looks good, certainly for small projects. If you need to compile the same source but with different options, then you'll need to keep the two object files separate, either by the method already given, or using directories:

Code:

all: cli gui

cli: cli/app.o cli/somecommonstuff.o

gui: somelib gui/app.o gui/somecommonstuff.o

cli/%.o : %.c
        CC CLI_FLAGS -DCLI $< -o $@

gui/%.o : %.c
        CC GUI_FLAGS -DGUI $< -o $@

If you're doing a big, multi-platform project using automake and friends, they support this sort of thing:
Code:

bin_PROGRAMS = myctrl mymon
sbin_PROGRAMS = lminst

myctrl_SOURCES = ctrlmain.cc Auth/lm.cc
myctrl_CXXFLAGS = -DRCFILE="\"/blah/blah/$(rcfile)\""
myctrl_LDADD = Gui/libgui.a Src/libctrl.a Comms/libcomms.a

mymon_SOURCES = monmain.cc
mymon_LDADD = Gui/libgui.a Src/libmon.a Comms/libcomms.a

lminst_SOURCES = Auth/lminst.cc Auth/lm.cc
lminst_CXXFLAGS = -DSHAREDIR="\"$(mydir)/\""

What that resolves to is a more complex (and far less readable) form of MerlinBlack's hand-written concept.

Enoch247 06-01-2012 10:01 AM

I like the per dir flags method. Maybe I'll run with that. I'm just surprised that there are no "cookbook" examples out there for this kind of pattern. I thought maybe it was because doing so violated some kinda of best practice.

I tried recursive make originally, but quickly realised why this practice is falling out of favour. Currently I have something similar to MerlinBlack's first example but I have outgrown this approach.


All times are GMT -5. The time now is 10:58 AM.