★ Bak Posted April 5, 2013 Report Posted April 5, 2013 I'm trying to create a makefile to build the modules part of Discretion, but I'm running into some trouble. The modules structure is fairly organized, so I was hoping to have a single makefile to create all of them, rather than a makefile for each individual module. The dependencies are like this: the makefile is in the modules directory. Inside this directory there is a folder for each module. I want the .so file produced to have the same name as the folder. Inside each folder can be a set of .h and .cpp files. A .o (or is it .obj for c++?) file should be created for each .cpp file which depends on the corresponding .cpp and .h files. The .so file should be created with the sane name as the directory, and depend on each of the .o files. The .so file should be placed in a different location "$(BIN_DIR)". After trying to do this for a few hours I got something like this: CC=g++ GLOBAL_CPPFLAGS= GLOBAL_LDFLAGS= BIN_DIR=../../bin/bin UNAME := $(shell uname) ifeq ($(UNAME), Linux) # Linux specific macros GLOBAL_CPPFLAGS += -DLINKING_LINUX else # Windows specific macros GLOBAL_CPPFLAGS += -DLINKING_WINDOWS endif ###################### # Rules MODULES = $(shell ls -d */) # remove the '/' from all directories MODULES := $(subst /,,$(MODULES)) # remove non modules which have directories MODULES := $(subst Shared,,$(MODULES)) MODULES := $(subst MapLoader,,$(MODULES)) MODULES := $(subst Module,,$(MODULES)) # generate variable for the final SO files: "$(BIN_DIR)/$(module).so" SO_FILES := $(foreach module,$(MODULES),$(BIN_DIR)/$(module).so) .PHONY : all clean modules modules: $(SO_FILES) all: modules # I want: each so file depends on all the .cpp and .h files in its directory %.so : ../../src/Modules/%/Animations.cpp echo deps = $^ When I run this, it works ok for the first module (Animations), since Animations.cpp is hardcoded in the makefile. What I actually want, though, is for the dependencies to be ALL the .cpp files (I'll eventually substitute .cpp for .o). When I replace the dependency line with this, though: %.so : ../../src/Modules/%/*.cpp echo deps = $^ It tells me there's no rule to make ../../bin/bin/Animations.so. If you want to try it out you can get the DiscretionClient source from mercurial (hg clone http://hg.code.sf.net/p/ss-discretion/client ss-discretion-client) and put the pasted makefile into src/Modules/ SubSpace Discretion: A Third Generation SubSpace Client
★ Bak Posted May 2, 2013 Author Report Posted May 2, 2013 I figured it out. You can use $(shell ls) in a makefile to spawn a shell and run commands, but that's to slow to do for every module (~35). So instead I made the following makefile, which scans the sources for known #includes so it knows what libraries to include automatically, as well as using gcc's dependency generation so exactly the correct files will be compiled when changes are detected. It also detects shared objects and includes them in the shared object files (.so or .dll) correctly. # A global makefile for creating Discretion. This should be in the src directory.# BaK, 3-28-2013 # standard variablesCC=g++LN=g++CPPFLAGS=-I./Modules/ -O3 -WallLDFLAGS=-shared # directoriesBIN_DIR=../bin/bin/MODULES_DIR=./Modules/ UNAME := $(shell uname) ifeq ($(UNAME), Linux)# Linux specific macrosLDFLAGS += -selse# Windows specific macrosLDFLAGS += -sendif ####################### Rules .PHONY : all clean # extract module namesMODULE_NAMES := $(wildcard $(MODULES_DIR)*)MODULE_NAMES := $(notdir $(MODULE_NAMES)) # remove non-modulesMODULE_NAMES := $(subst Shared ,,$(MODULE_NAMES)) SO_FILES := $(addprefix $(BIN_DIR), $(MODULE_NAMES))SO_FILES := $(addsuffix .so,$(SO_FILES)) all: $(SO_FILES) clean: rm -vf $(BIN_DIR)*.so $(MODULES_DIR)*/*.o $(MODULES_DIR)*/*.d $(MODULES_DIR)*/*.deps # pull in dependency info for *existing* .o files (redirect errors away from terminal in case .d files don't exist)DEP_FILES := $(shell ls $(MODULES_DIR)*/*.d 2> .junk ; rm -f .junk)-include $(DEP_FILES) define make_so# param 1 is name of so file # general rule for making .so files, first make .o.deps and .ld.deps$(BIN_DIR)$(1).so: $(MODULES_DIR)$(1)/$(1).o.deps $(MODULES_DIR)$(1)/$(1).ld.deps $(CC) $(LDFLAGS) -o $$@ `cat $(MODULES_DIR)$(1)/$(1).o.deps` `cat $(MODULES_DIR)$(1)/$(1).ld.deps` ### tracks which libraries should be linked with the .so #### 1. create a blank .ld.deps file# 2. create an entry if SDL.h is detected# 3. create an entry if SDL_net.h is detected# 4. create an entry if SDL_image.h is detected# 5. create and entry if zlib.h is detected$(MODULES_DIR)$(1)/$(1).ld.deps: $(MODULES_DIR)$(1)/*.cppecho -n > $(MODULES_DIR)$(1)/$(1).ld.deps && \\if [ `cat $(MODULES_DIR)$(1)/*.cpp | grep SDL.h -c` -ne 0 ]; \then echo -n "-lSDL " >> $(MODULES_DIR)$(1)/$(1).ld.deps; fi && \\if [ `cat $(MODULES_DIR)$(1)/*.cpp | grep SDL_net.h -c` -ne 0 ]; \then echo -n "-lSDL_net " >> $(MODULES_DIR)$(1)/$(1).ld.deps; fi && \\if [ `cat $(MODULES_DIR)$(1)/*.cpp | grep SDL_image.h -c` -ne 0 ]; \then echo -n "-lSDL_image " >> $(MODULES_DIR)$(1)/$(1).ld.deps; fi && \\if [ `cat $(MODULES_DIR)$(1)/*.cpp | grep zlib.h -c` -ne 0 ]; \then echo -n "-lzdll " >> $(MODULES_DIR)$(1)/$(1).ld.deps; fi #### tracks which .o files need to be built and included in the .so #### 1. create a .o.deps entry for every .cpp file in the module's directory# 2. create .o.deps entry if StringManip.h is used# 3. create .o.deps entry if LittleEndian.h is used# 4. create the .so.deps file from the now complete .o.deps file# 5. recursive call to make so that the .so dependecies get included and the proper .o files get made$(MODULES_DIR)$(1)/$(1).o.deps: $(MODULES_DIR)$(1)/*.cpp+ ls $(MODULES_DIR)$(1)/*.cpp | tr '\n' ' ' | sed -e 's/\.cpp/\.o/g' > $(MODULES_DIR)$(1)/$(1).o.deps && \\if [ `cat $(MODULES_DIR)$(1)/*.cpp | grep StringManip.h -c` -ne 0 ]; \then echo -n " "$(MODULES_DIR)Shared/StringManip.o >> $(MODULES_DIR)$(1)/$(1).o.deps; fi && \\if [ `cat $(MODULES_DIR)$(1)/*.cpp | grep LittleEndian.h -c` -ne 0 ]; \then echo -n " "$(MODULES_DIR)Shared/LittleEndian.o >> $(MODULES_DIR)$(1)/$(1).o.deps; fi && \\echo -n "$(BIN_DIR)$(1).so: " > $(MODULES_DIR)$(1)/$(1).so.deps; cat $(MODULES_DIR)$(1)/$(1).o.deps >> $(MODULES_DIR)$(1)/$(1).so.deps && \\$(MAKE) `cat $(MODULES_DIR)$(1)/$(1).o.deps` --no-print-directory # includes the generated dependencies for the .so (this takes effect in the recursive make call from the .o.deps rule)-include $(MODULES_DIR)$(1)/$(1).so.deps endef $(foreach modname,$(MODULE_NAMES),$(eval $(call make_so,$(modname)))) #for number in 1 2 3 4 ; do \# ./a.out $$number ; \#done %.o : %.cpp$(CC) -MMD -c $(CPPFLAGS) $< -o $@ SubSpace Discretion: A Third Generation SubSpace Client
★ Bak Posted May 2, 2013 Author Report Posted May 2, 2013 I wanted to edit the above since apparently pasting into code blocks didn't work. When I hit edit, though, both Chrome and Iexplorer freeze, so I've just tried again here with a quote block. # A global makefile for creating Discretion. This should be in the src directory.# BaK, 3-28-2013 # standard variablesCC=g++LN=g++CPPFLAGS=-I./Modules/ -O3 -WallLDFLAGS=-shared # directoriesBIN_DIR=../bin/bin/MODULES_DIR=./Modules/ UNAME := $(shell uname) ifeq ($(UNAME), Linux)# Linux specific macrosLDFLAGS += -selse# Windows specific macrosLDFLAGS += -sendif ####################### Rules .PHONY : all clean # extract module namesMODULE_NAMES := $(wildcard $(MODULES_DIR)*)MODULE_NAMES := $(notdir $(MODULE_NAMES)) # remove non-modulesMODULE_NAMES := $(subst Shared ,,$(MODULE_NAMES)) SO_FILES := $(addprefix $(BIN_DIR), $(MODULE_NAMES))SO_FILES := $(addsuffix .so,$(SO_FILES)) all: $(SO_FILES) clean: rm -vf $(BIN_DIR)*.so $(MODULES_DIR)*/*.o $(MODULES_DIR)*/*.d $(MODULES_DIR)*/*.deps # pull in dependency info for *existing* .o files (redirect errors away from terminal in case .d files don't exist)DEP_FILES := $(shell ls $(MODULES_DIR)*/*.d 2> .junk ; rm -f .junk)-include $(DEP_FILES) define make_so# param 1 is name of so file # general rule for making .so files, first make .o.deps and .ld.deps$(BIN_DIR)$(1).so: $(MODULES_DIR)$(1)/$(1).o.deps $(MODULES_DIR)$(1)/$(1).ld.deps $(CC) $(LDFLAGS) -o $$@ `cat $(MODULES_DIR)$(1)/$(1).o.deps` `cat $(MODULES_DIR)$(1)/$(1).ld.deps` ### tracks which libraries should be linked with the .so #### 1. create a blank .ld.deps file# 2. create an entry if SDL.h is detected# 3. create an entry if SDL_net.h is detected# 4. create an entry if SDL_image.h is detected# 5. create and entry if zlib.h is detected$(MODULES_DIR)$(1)/$(1).ld.deps: $(MODULES_DIR)$(1)/*.cppecho -n > $(MODULES_DIR)$(1)/$(1).ld.deps && \\if [ `cat $(MODULES_DIR)$(1)/*.cpp | grep SDL.h -c` -ne 0 ]; \then echo -n "-lSDL " >> $(MODULES_DIR)$(1)/$(1).ld.deps; fi && \\if [ `cat $(MODULES_DIR)$(1)/*.cpp | grep SDL_net.h -c` -ne 0 ]; \then echo -n "-lSDL_net " >> $(MODULES_DIR)$(1)/$(1).ld.deps; fi && \\if [ `cat $(MODULES_DIR)$(1)/*.cpp | grep SDL_image.h -c` -ne 0 ]; \then echo -n "-lSDL_image " >> $(MODULES_DIR)$(1)/$(1).ld.deps; fi && \\if [ `cat $(MODULES_DIR)$(1)/*.cpp | grep zlib.h -c` -ne 0 ]; \then echo -n "-lzdll " >> $(MODULES_DIR)$(1)/$(1).ld.deps; fi #### tracks which .o files need to be built and included in the .so #### 1. create a .o.deps entry for every .cpp file in the module's directory# 2. create .o.deps entry if StringManip.h is used# 3. create .o.deps entry if LittleEndian.h is used# 4. create the .so.deps file from the now complete .o.deps file# 5. recursive call to make so that the .so dependecies get included and the proper .o files get made$(MODULES_DIR)$(1)/$(1).o.deps: $(MODULES_DIR)$(1)/*.cpp+ ls $(MODULES_DIR)$(1)/*.cpp | tr '\n' ' ' | sed -e 's/\.cpp/\.o/g' > $(MODULES_DIR)$(1)/$(1).o.deps && \\if [ `cat $(MODULES_DIR)$(1)/*.cpp | grep StringManip.h -c` -ne 0 ]; \then echo -n " "$(MODULES_DIR)Shared/StringManip.o >> $(MODULES_DIR)$(1)/$(1).o.deps; fi && \\if [ `cat $(MODULES_DIR)$(1)/*.cpp | grep LittleEndian.h -c` -ne 0 ]; \then echo -n " "$(MODULES_DIR)Shared/LittleEndian.o >> $(MODULES_DIR)$(1)/$(1).o.deps; fi && \\echo -n "$(BIN_DIR)$(1).so: " > $(MODULES_DIR)$(1)/$(1).so.deps; cat $(MODULES_DIR)$(1)/$(1).o.deps >> $(MODULES_DIR)$(1)/$(1).so.deps && \\$(MAKE) `cat $(MODULES_DIR)$(1)/$(1).o.deps` --no-print-directory # includes the generated dependencies for the .so (this takes effect in the recursive make call from the .o.deps rule)-include $(MODULES_DIR)$(1)/$(1).so.deps endef $(foreach modname,$(MODULE_NAMES),$(eval $(call make_so,$(modname)))) #for number in 1 2 3 4 ; do \# ./a.out $$number ; \#done %.o : %.cpp$(CC) -MMD -c $(CPPFLAGS) $< -o $@ SubSpace Discretion: A Third Generation SubSpace Client
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now