简体   繁体   中英

Makefile working in Linux but not under Windows, can't find files in subdirectory

I have a makefile (gnu make) working under linux, but when porting it to windows it does not work. The goal of the makefile is to make all the *.cpp file that reside in different subdirectories and compile them into *.obj files in a single BUILD_DIR.

Between linux and windows I only adjusted the SOURCES variable, the linux line is shown but commented. When I check all the names and directories they show the same (relative paths in their perspective notation) and what I expect.

The "error message" I get on windows is: make: *** No rule to make target 'DEM.cpp', needed by 'DEM.obj'. Stop.

In debug mode it says: File 'DEM.cpp' does not exist. (which it obviously does)

On linux it finds the file via the VPATH, in debug mode it says: No need to remake target 'DEM.cpp'; using VPATH name './Code/DEM.cpp'.

The subdirectory structure in both linux and windows is the same and the makefile is run from the same location.

Question: What is going wrong here, I have the feeling it has something to do with VPATH being handled differently on windows but I am not certain.

My makefile is:

# MAKEFILE    
# Some makefile settings 
SHELL = /bin/sh     #Make sure the shell is the standard shell
.SUFFIXES:      #Clear al implicit suffixes
.SUFFIXES: .cpp .obj    #Set used suffixes

# Variable Declaration
CXX := g++
BUILD_DIR = .\bin\Release
PROGRAM_NAME := DEM.exe

#SOURCES := $(shell find . -name '*.cpp')                   #All *.cpp files with directory (LINUX style)
SOURCES := $(shell FORFILES /S /M *.cpp /C "CMD /C ECHO @relpath")  #All *.cpp files with directory
NAMES := $(notdir $(basename $(SOURCES)))                   #Get all files names of the *.cpp files without extensions
OBJECTS := $(addsuffix .obj, $(NAMES))                      #Get the to be generate *.o files without directory
SRC_DIRS := $(dir $(SOURCES))                               #All the directory in which the sources are found
VPATH := $(SRC_DIRS) $(BUILD_DIR)

.PHONY: all
all: build                                  #Standard entry point, run release
    @echo "BUILD DONE"

.PHONY: build
    build: $(PROGRAM_NAME)
    @echo "BUILD DONE"

$(PROGRAM_NAME): $(OBJECTS)
    @echo "Link executable"
    $(CXX) -o $(BUILD_DIR)/$(PROGRAM_NAME) $(addprefix $(BUILD_DIR)/,$(OBJECTS))

$(OBJECTS): %.obj: %.cpp
    @echo "Compile into object code: $<"
    ${CXX} $(CXXFLAGS)  -c $< -o $(BUILD_DIR)/$@    #Compiles object code and places it in the $(BUILD_DIR)

Update 1: Based on the comment of some programmer dude , I ran it with -p, and got the following interesting result:

# Not a target:
DEM.cpp:
#  Implicit rule search has been done.
#  File does not exist.
#  File has not been updated.

# Not a target:
World.cpp:
#  Implicit rule search has not been done.
#  Modification time never checked.
#  File has not been updated.

# Lot more targets below

It seems only to not find DEM.cpp but it finds everything else. DEM.cpp resides in C:\\Users\\dklomp\\Documents\\Programming\\C++ Source\\DEM\\DEM\\Code, but should resolve to .\\Code\\ Most other files reside in subdirectories in Code. But stdafx.cpp also resides in .\\Code\\ and there is no problem finding it.

Can it be a name clash with the directory name DEM being similar to DEM.cpp

Update 2: For information and closure. I had already check the VPATH by reading the variable by printing it this seemed to give the correct information. However if i read it with @(info $(VPATH)) it seemet empty:

@echo "VPATH print variable: "
@echo "$(VPATH)"
@echo "VPATH print info: "
$(info VPATH)

gave:

"VPATH print variable: "
"./Code/InputOutput/ ./Code/InputOutput/ ./Code/InputOutput/ 
./Code/InputOutput/ ./Code/ ./Code/ ./Code/Models/ ./Code/Models/ 
./Code/Forces/ ./Code/Forces/ ./Code/Forces/ ./Code/Forces/ ./Code/Forces/ 
./Code/Forces/ ./Code/Forces/ ./Code/Forces/ ./Code/Forces/ ./Code/Tools/ 
./Code/Tools/ ./Code/Tools/ ./Code/Tools/ ./Code/Solvers/ ./Code/Solvers/ 
./Code/Solvers/ ./Code/World/ ./Code/World/ ./Code/World/ ./Code/World/ 
./Code/World/ ./Code/Interactions/ ./Code/Interactions/ ./Code/Interactions/ 
./Code/Interactions/ ./Code/Interactions/ ./Code/Interactions/                                                               
bin\Release"
"VPATH print info: "

Indeed with a lot of repetitions (will use the sort suggestion of hardcoreHenry) but it seemed oke. However the VPATH info is empty for some reason.

However implementing the proposed solution by code_fodder and removing all the inline code comments works. The inline code comments on the variable declaration do not seem to matter, those in the rules section do for windows, linux seems to handle inline code comments fine everywhere.

As usually thanks for the help and suggestions.

I tested this in a path that had spaces before the current location (eg like d:\\path with spaces\\myfolder\\sub_folder1\\sub_folder2\\ ).

I think there is some issue with the FORFILES syntax/output - at least I could not get it to work. As soon as I used the more generic rwildcard from second answer from here it started to work quite well. Then I added rules to create/clean your output folder.

Also I removed any inline comments, since I am not 100% sure they are valid because they leave space characters everywhere and makefile is not very tolerant of that... IE make-sure you don't leave any trailing white space on any lines.

Also - this all assumes its gnu-make and not nmake

# MAKEFILE    
# Some makefile settings 
SHELL = /bin/sh
.SUFFIXES:
.SUFFIXES: .cpp .obj

# Variable Declaration
CXX := g++
BUILD_DIR = .\bin\Release
PROGRAM_NAME := DEM.exe

# Define a recursive wild card function that is portable.
rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d))

#SOURCES := $(shell FORFILES /S /M *.cpp /C "CMD /C ECHO @relpath")
SOURCES := $(call rwildcard, ./, *.cpp)
$(info SOURCES: $(SOURCES))
NAMES := $(notdir $(basename $(SOURCES)))
OBJECTS := $(addsuffix .obj, $(NAMES))
SRC_DIRS := $(dir $(SOURCES))
VPATH := $(SRC_DIRS) $(BUILD_DIR)

.PHONY: all
all: create_dirs build
    @echo "BUILD DONE"

# Has an order dependency on create_dirs to ensure that happens first, and so 
# it works with parallel build (e.g. `make -j4`)
.PHONY: build
build: $(PROGRAM_NAME) | create_dirs
    @echo "BUILD DONE"

$(PROGRAM_NAME): $(OBJECTS)
    @echo "Link executable"
    $(CXX) -o $(BUILD_DIR)/$(PROGRAM_NAME) $(addprefix $(BUILD_DIR)/,$(OBJECTS))

$(OBJECTS): %.obj: %.cpp
    @echo "Compile into object code: $<"
    ${CXX} $(CXXFLAGS)  -c $< -o $(BUILD_DIR)/$@

.PHONY: create_dirs
create_dirs:
    @echo "creating dirs"
    mkdir -p $(BUILD_DIR)

.PHONY: clean
clean:
    @echo "cleaning"
    rm -rf $(BUILD_DIR)

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