简体   繁体   中英

Make and c++ files, “includes” in the cpp

This is my current makefile:

# Compiler #
CXX      = g++
DEBUG    = -g
LFLAGS   =
CXXFLAGS = -Wall

# Directories #
SRCDIR   = src/
INCDIR   = include/
BUILDDIR = build/
BINDIR   = bin/

# Objects #
OBJ_NAMES = main.o dfa.o dfaException.o state.o
OBJS       = $(addprefix $(BUILDDIR), $(OBJ_NAMES))

# Output #
NAME = pract3
TARGET = $(BINDIR)pract3

# Clean #
ifeq ($(OS),Windows_NT)
    RM = del /q /s $(BUILDDIR:/=\)*.o $(BINDIR:/=\)$(NAME)*
else
    RM = rm -rf $(BUILDDIR)*.o $(TARGET)*
endif

# Files #
$(TARGET): $(OBJS)
    $(CXX) $(CXXFLAGS) $(LFLAGS) $(OBJS) -o $(TARGET)

$(BUILDDIR)%.o: $(SRCDIR)%.cpp
    $(CXX) $(CXXFLAGS) $(LFLAGS) -c $< -o $@

clean:
    $(RM)

And this is my project tree:

Porject/

    bin/

    build/

    doc/
        ...

    include/
        connection.hpp
        dfa.hpp
        dfaException.hpp
        state.hpp

    src/
        dfa.cpp
        dfaException.cpp
        main.cpp
        state.cpp

    Makefile
    Readme

Now, I'm having three "problems".

First I want my makefile to create the bin and build directories just in case they aren't. I guess I just have to use:

mkdir $(BUILDDIR)
mkdir $(BINDIR)

But where should I put them ? And also, how can I prevent mkdir and rm (or del in windows) messages like "Cant find ..." or "x directory already exists ... "

Second, I'm guessing I can read the objects name from src/ (converting the .cpp to .o), but how can I read the file names from a directory ?

Last, I have one template class: connection.hpp (all functions are in the header). This file is included in state.hpp using: #include "../include/connection.hpp" . I ran make one time with all correct and then I purposely make a syntax error in connection.hpp . Then I ran make again, but It only compiled the target file using the .o files in build without any error. Everytime I want to edit connection.hpp I have to use make clean and then make . Is there any better way to do this ?

  1. If you need a directory to exist before you can proceed, simply put

     mkdir -p ${DIRECTORY} 

    before you need it in your rule. If the directory already exists, mkdir -p will happily do nothing.

    Likewise, if you use rm -f FILE , it should not complain if FILE does not exist in the first place.

  2. There is no portable way to create a variable that holds the names of all files in a directory. But you are already using GNU Make features anyway, so you can just use

     SOURCES = $(wildcard ${SRCDIR}/*.cpp) 

    and then

     OBJECTS = $(SOURCES:.cpp=.o) 

    to transform them into object file names. You'll probably want to replace the leading directory name as well, I guess.

  3. You didn't list any *.hpp files as prerequisites in your make file. You can either manually add them like

     foo.o: foo.cpp bar.hpp baz.hpp 

    but that becomes unpleasant very quickly. Another trick is to use the compiler to tell you the headers (transitively) #include d by a file. If you are using GCC, you can run

     gcc -MM foo.cpp 

    to have it output above make-file snippet. You can put a pattern rule like the following

     %.deps: %.cpp ${CXX} -MM ${CPPFLAGS} $< > $@ 

    into your make-file and then include the generated *.deps files.

     include $(SOURCES:.cpp=.deps) 

    GNU Make will be smart enough to first parse the make-file, recognize that the *.deps files don't exist and therefore cannot be include d but figure out that there is a rule to generate them. So it will execute that rule and then continue parsing the make-file.

    I have learned that trick from Peter Miller's great article Recursive Make Considered Harmful which is a good read if you want to learn how to write good make-files.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM