Search code examples
makefilefreebsdc89

How do I read source files from a directory and create object files into another folder in a makefile?


I have the following source files:

% ls 
data_lexicon.c  data_lexicon.h  lex.l           makefile

And the following makefile:

% cat makefile
CC              = cc
CFLAGS          = -Wall -std=c89
LDFLAGS         = -ll
OBJFILES        = lex.o data_lexicon.o
TARGET          = lexical_analyzer_1

all:            $(TARGET) lex.c

lex.c:          lex.l data_lexicon.h
                lex -olex.c lex.l

$(TARGET):      $(OBJFILES)
                $(CC) $(CFLAGS) -o $(TARGET) $(OBJFILES) $(LDFLAGS)

clean:
                rm -f $(OBJFILES) lex.c $(TARGET)

If I do make all I get:

% ls 
data_lexicon.c          data_lexicon.o          lex.l
lexical_analyzer_1      data_lexicon.h          lex.c
lex.o                   makefile

So far so good.

However, I would like to move the source files (data_lexicon.c, data_lexicon.h, lex.l) to a folder src and generate the intermediate files (data_lexicon.o lex.c, lex.o) into a obj folder.

I create both folders but I do not understand how the makefile file shall be configured.

I am using FreeBSD make, so the more portable the solution given the better.


Solution

  • However, I would like to move the source files (data_lexicon.c, data_lexicon.h, lex.l) to a folder src and generate the intermediate files (data_lexicon.o lex.c, lex.o) into a obj folder.

    It never ceases to amaze me how people insist on making extra work for themselves. You can certainly do what you describe, but it will require writing explicit rules for the object files.

    First of all, however, you need to understand that make itself doesn't really know anything about directories. (Traditional make doesn't, anyway. GNU make and perhaps others know a little about them.) That is, it doesn't have any sense of varying directories against which it resolves file names. Rather, every target name is resolved against make's working directory. If you want to refer to something in a subdirectory, then you must say so. To begin with:

    OBJFILES        = obj/lex.o obj/data_lexicon.o
    

    Similar goes for target and prerequisite names in rules:

    obj/lex.c:      src/lex.l src/data_lexicon.h
                    lex -o$@ src/lex.l
    

    That's also one reason to favor make's automatic variables, such as the $@ in the above rule representing the name of the target being built.

    Your makefile presently relies on make's built-in rule for building object files from corresponding C source files, but "corresponding" means target and prerequisite names are identical, including any path components, except for the suffixes (.c vs .o). You will no longer have that correspondence for data_lexicon.o, so you will need to write an explicit rule for it building it. This part is left as an exercise.