Makefile: no rule to make target

前端 未结 3 1605
一个人的身影
一个人的身影 2021-01-15 18:28

I was looking for a solution on this site and also tried google for some time now, but somehow I can\'t get it to work.

My source should be in the src directory and

相关标签:
3条回答
  • 2021-01-15 18:38

    You actually have a couple if incorrect things above.

    First you write My error was, that I was assuming that the pattern %.o matches ANY pattern ending with .o which it doesn't; that's not true. The pattern does match any string ending in .o. However, the pattern character % that is matched on the target side is replaced on the prerequisite side with the identical string. So if you have a target obj/task.o and it matches the pattern %.o then the stem (what the manual calls it) will be obj/task, and when the prerequisite is %.c that means that make will look for a prerequisite obj/task.c. Since there isn't one, and make doesn't know how to build one, that rule is discarded as not applying. When writing pattern rules you must write them so ONLY the identical parts of the names match the pattern character (%). ALL non-identical parts, including directories, must be specified explicitly.

    Second, the rule $(OBJ) : $(SRC) is really not right. That line says that each object file depends on all the source files, so whenever any single source file changes all the object files will be recompiled. That's really not what you want (if that IS what you want you don't need make: you can just write a simple shell script). I don't know what you mean by since the rules is empty it invokes the pattern rule; you don't need this to invoke the pattern rule. The target depends on $(OBJ), and each object file depends on its source file (due to the pattern). You don't need this line at all.

    Third, I don't know why you are trying to construct .asm files rather than just compiling directly from source to object, but if you really want them it would be cleaner and more "make-like" to create a separate pattern rule to build them: create a pattern rule $(OBJDIR)/%.o : $(OBJDIR)/%.asm and a rule $(OBJDIR)/%.asm : $(SRCDIR)/%.c. If you want the ASM files to be products of the build you should declare them as a prerequisite of all or similar, otherwise they'll be deleted as intermediate files.

    Fourth, using things like basename is unnecessary. There are lots of automatic make variables that can be used instead. For example, $* expands to the stem, so you could write $(OBJDIR)/$*.asm. Of course if you make a separate pattern rule for ASM files you can just use $@ or $< directly. There are various make functions that can also be used; see the manual.

    Fifth, you define a variable containing a header file, DEP, but then never use it. Because it's not used, if you change that file nothing would be rebuilt. If you know that all the source files include every header you can use $(OBJ) : $(DEP) to define that; but it does mean (as in the second point above) that any change to any header causes all objects to recompile. You would be better off auto-generating the prerequisites; since you're using GCC this is quite simple.

    Sixth, you're using C++ files (xxx.cpp) but you're using the C compiler. This will not work (the link line will fail: although the compiler can see you're compiling a C++ file and do the right thing, even if you call gcc, when you link a bunch of objects together it has no idea if those were C objects or C++ objects (or FORTRAN or whatever) so you MUST use the C++ front-end to link or it won't pull in the right C++ libraries). You should be using the make variable CXX to build C++ code, not CC, and setting it to g++ not gcc.

    Seventh, you don't need .SUFFIXES: .c .o to use pattern rules. They are only needed for suffix rules, which you don't have here. You can keep the plain .SUFFIXES: though to disable built-in pattern matching which is a slight performance improvement.

    Finally, you'll note you don't actually need the $(SRC) variable because make can infer it from the pattern rules. However, if you wanted to have your makefile less onerous to change, you could construct the contents of the OBJ variable from the SRC variable, like SRC = nohupshd.cpp task.cpp then OBJ = $(patsubst %.c,$(OBJDIR)/%.o,$(SRC)).

    So, all-in, this is how I would recommend you write your makefile (I don't include the auto-generated dependencies here though):

    .SUFFIXES:
    
    CXX :=      g++
    CXXFLAGS := -O2 -g -Wall -fmessage-length=0
    
    OBJDIR :=   obj
    SRCDIR :=   src
    
    TARGET :=   nohupshd
    SRC :=      nohupshd.cpp task.cpp
    DEP :=      src/task.h
    LIBS :=
    
    # ----
    
    OBJ :=      $(patsubst %.cpp,$(OBJDIR)/%.o,$(SRC))
    ASM :=      $(patsubst %.cpp,$(OBJDIR)/%.asm,$(SRC))
    
    .PHONY: all clean
    
    all: $(TARGET) $(ASM)
    
    $(TARGET): $(OBJ)
            $(CXX) -o $@ $^ $(LIBS)
    
    clean:
            rm -f $(OBJDIR)/* $(TARGET)
    
    $(OBJDIR)/%.o : $(SRCDIR)/%.asm
            $(CXX) $(CXXFLAGS) -c -x assembler-with-cpp $< -o $@
    
    $(OBJDIR)/%.asm : $(SRCDIR)/%.cpp
            $(CXX) $(CPPFLAGS) -S $< -o $@
    
    0 讨论(0)
  • 2021-01-15 18:50

    Don't repeat the directory names in the compiler line. $< and $@ already have the directory names.

    $(OBJDIR)/%.o: $(SRCDIR)/%.cpp
        $(CC) -S $< -o $@
        $(CC) -c $< -o $@
    
    0 讨论(0)
  • 2021-01-15 19:00

    So finally I found the answer on how to write this makefile, for an exaplanation of my mistakes look at the posting I marked as correct answer:

    The resulting makefile looks like this, and for completeness I post it here including dependencies for header files (remove the ASM parts if you don't need 'em):

    .SUFFIXES:
    .SUFFIXES: .o .cpp
    .SUFFIXES: .o .d
    
    CC := g++
    LNK:= ar
    CXXFLAGS =  -O2 -g -Wall -fmessage-length=0
    
    OBJDIR:=        obj
    SRCDIR:=        src
    HDIR:=      include
    
    INCLUDE_PATHS:= -Iinclude -Iinclude/interfaces -Iinclude/support
    
    CPP_FILES := propertyfile/propertyfile.cpp \
                propertyfile/propertyitem.cpp \
                propertyfile/propertyfactory.cpp
    
    OBJ :=  $(patsubst %.cpp,$(OBJDIR)/%.o, $(CPP_FILES))
    SRC :=  $(patsubst %.cpp,$(SRCDIR)/%.o, $(CPP_FILES))
    ASM :=      $(patsubst %.cpp, $(OBJDIR)/$*.asm, $(CPP_FILES))
    
    LIBS:=      
    
    TARGET:=    libsupport.a
    
    all:    $(TARGET)
    
    $(TARGET):  $(OBJ)
        @echo "Linking..."
        @$(LNK) rvs $(TARGET) $(OBJ)
        @cp $(TARGET) ../lib
        @cp -r include ..
    
    clean:
        rm -f $(OBJ) $(ASM) $(TARGET)
    
    -include $(patsubst %.cpp,$(OBJDIR)/%.d, $(CPP_FILES))
    
    $(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(OBJDIR)/%.d 
        @mkdir -p `dirname $@`
        $(CC) $(CXXFLAGS) -S $< -o $(OBJDIR)/$*.asm $(INCLUDE_PATHS)
        $(CC) $(CXXFLAGS) -c $< -o $@ $(INCLUDE_PATHS)
    
    $(OBJDIR)/%.d: $(SRCDIR)/%.cpp 
        $(CC) $(CXXFLAGS) -MM -MT $@ -MF $(OBJDIR)/$*.d -c $< $(INCLUDE_PATHS)  
    

    I hope this helps other user. All examples that I found were either extremly simple and listed multiple files individually and not part of a rule, but didn't really explain how it works, or were so complicated that I couldn't find out how it can help me.

    0 讨论(0)
提交回复
热议问题