.DEFAULT_GOAL := all # --- Input variables --- BUILD ?= release ifeq ($(findstring $(BUILD),debug release),) $(error BUILD must be set to debug or release) endif # Build all executables by default. APPS ?= demo # If the VERBOSE flag isn't set, then mute superfluous output. ifeq ($(VERBOSE),) HUSH_COMPILE = @echo "Compiling $<"; HUSH_LINK = @echo "Linking $@"; HUSH_GENERATE = @echo "Generating $@"; HUSH_CLEAN = @ endif # --- Internal variables --- ARCH := $(shell uname -p) SRC_ROOT := $(abspath ../../src) OUTPUT_DIR := $(abspath .) INTERMEDIATE_DIR := $(OUTPUT_DIR)/obj BUILD_DIR := $(INTERMEDIATE_DIR)/$(BUILD) ARFLAGS = r LDFLAGS = -lX11 -lGL -pthread -lasound -ldl # Always enable debug information. CFLAGS += -g # Enable extra warnings and make all warnings into errors. CFLAGS += -Wextra -Werror # Flags to generate dependency information. CFLAGS += -MD -MP -MT $@ # Predefined flags. ifeq ($(BUILD), debug) CFLAGS += -D_DEBUG CFLAGS += -D_GLIBCXX_DEBUG endif # Enable compiler optimizations for everything except debug. # Note that a very aggresssive optimization level is used and it may not be # valid for all standard compliant programs. Reduce this level on individual # files or modules as needed. ifneq ($(BUILD), debug) CFLAGS += -Ofast endif # Flag to turn on extended instruction sets for the compiler. CFLAGS += -msse2 # Let C++ inherit all C flags. CXXFLAGS = $(CFLAGS) -I$(SRC_ROOT) # Enable C++20 CXXFLAGS += -std=c++20 # Vulkan config CFLAGS += -DVK_USE_PLATFORM_XLIB_KHR CFLAGS += -DVMA_STATIC_VULKAN_FUNCTIONS=1 CFLAGS += -I$(SRC_ROOT)/third_party/vulkan/include CXXFLAGS += -I$(SRC_ROOT)/third_party/glslang # --- Internal functions --- app_exe = $(OUTPUT_DIR)/$(1)_$(ARCH)_$(BUILD) objs_from_src = $(patsubst $(SRC_ROOT)/%, $(BUILD_DIR)/%.o, $(basename $(1))) objs_from_src_in = $(call objs_from_src, $(shell find $(1) -name "*.cc" -o -name "*.cpp" -o -name "*.c")) # --- Base --- BASE_SRC := \ $(SRC_ROOT)/base/collusion_test.cc \ $(SRC_ROOT)/base/log.cc \ $(SRC_ROOT)/base/task_runner.cc \ $(SRC_ROOT)/base/thread_pool.cc \ $(SRC_ROOT)/base/timer.cc BASE_LIB := $(BUILD_DIR)/libengine.a BASE_OBJS := $(call objs_from_src, $(BASE_SRC)) LIBS += $(BASE_LIB) OBJS += $(BASE_OBJS) $(BASE_LIB): $(BASE_OBJS) # --- Engine --- ENGINE_SRC := \ $(SRC_ROOT)/engine/animatable.cc \ $(SRC_ROOT)/engine/animator.cc \ $(SRC_ROOT)/engine/asset/font.cc \ $(SRC_ROOT)/engine/asset/image.cc \ $(SRC_ROOT)/engine/asset/mesh.cc \ $(SRC_ROOT)/engine/asset/shader_source.cc \ $(SRC_ROOT)/engine/asset/sound.cc \ $(SRC_ROOT)/engine/audio/audio_bus.cc \ $(SRC_ROOT)/engine/audio/audio_mixer.cc \ $(SRC_ROOT)/engine/audio/audio_sink_alsa.cc \ $(SRC_ROOT)/engine/audio/mixer_input.cc \ $(SRC_ROOT)/engine/audio/sinc_resampler.cc \ $(SRC_ROOT)/engine/drawable.cc \ $(SRC_ROOT)/engine/engine.cc \ $(SRC_ROOT)/engine/image_quad.cc \ $(SRC_ROOT)/engine/persistent_data.cc \ $(SRC_ROOT)/engine/platform/asset_file_linux.cc \ $(SRC_ROOT)/engine/platform/asset_file.cc \ $(SRC_ROOT)/engine/platform/platform_linux.cc \ $(SRC_ROOT)/engine/renderer/geometry.cc \ $(SRC_ROOT)/engine/renderer/opengl/renderer_opengl_linux.cc \ $(SRC_ROOT)/engine/renderer/opengl/renderer_opengl.cc \ $(SRC_ROOT)/engine/renderer/renderer_types.cc \ $(SRC_ROOT)/engine/renderer/shader.cc \ $(SRC_ROOT)/engine/renderer/texture.cc \ $(SRC_ROOT)/engine/renderer/vulkan/renderer_vulkan_linux.cc \ $(SRC_ROOT)/engine/renderer/vulkan/renderer_vulkan.cc \ $(SRC_ROOT)/engine/renderer/vulkan/vulkan_context_linux.cc \ $(SRC_ROOT)/engine/renderer/vulkan/vulkan_context.cc \ $(SRC_ROOT)/engine/solid_quad.cc \ $(SRC_ROOT)/engine/sound_player.cc ENGINE_LIB := $(BUILD_DIR)/libengine.a ENGINE_OBJS := $(call objs_from_src, $(ENGINE_SRC)) LIBS += $(ENGINE_LIB) OBJS += $(ENGINE_OBJS) $(ENGINE_LIB): $(ENGINE_OBJS) # --- Third-party --- # Ignore warnings. THIRD_PARTY_CFLAGS = $(CFLAGS) THIRD_PARTY_CFLAGS := $(filter-out -Wextra -Werror, $(THIRD_PARTY_CFLAGS)) THIRD_PARTY_CXXFLAGS = $(CXXFLAGS) THIRD_PARTY_CXXFLAGS := $(filter-out -Wextra -Werror, $(THIRD_PARTY_CXXFLAGS)) THIRD_PARTY_SRC := \ $(SRC_ROOT)/third_party/glew/glew.c \ $(SRC_ROOT)/third_party/glslang/glslang/GenericCodeGen/CodeGen.cpp \ $(SRC_ROOT)/third_party/glslang/glslang/GenericCodeGen/Link.cpp \ $(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/attribute.cpp \ $(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/Constant.cpp \ $(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/glslang_tab.cpp \ $(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/InfoSink.cpp \ $(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/Initialize.cpp \ $(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/Intermediate.cpp \ $(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/intermOut.cpp \ $(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/IntermTraverse.cpp \ $(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/iomapper.cpp \ $(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/limits.cpp \ $(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/linkValidate.cpp \ $(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/parseConst.cpp \ $(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/ParseContextBase.cpp \ $(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/ParseHelper.cpp \ $(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/PoolAlloc.cpp \ $(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/preprocessor/Pp.cpp \ $(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/preprocessor/PpAtom.cpp \ $(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/preprocessor/PpContext.cpp \ $(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp \ $(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/preprocessor/PpTokens.cpp \ $(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/propagateNoContraction.cpp \ $(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/reflection.cpp \ $(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/RemoveTree.cpp \ $(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/Scan.cpp \ $(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/ShaderLang.cpp \ $(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/SpirvIntrinsics.cpp \ $(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/SymbolTable.cpp \ $(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/Versions.cpp \ $(SRC_ROOT)/third_party/glslang/glslang/OSDependent/Unix/ossource.cpp \ $(SRC_ROOT)/third_party/glslang/OGLCompilersDLL/InitializeDll.cpp \ $(SRC_ROOT)/third_party/glslang/SPIRV/disassemble.cpp \ $(SRC_ROOT)/third_party/glslang/SPIRV/doc.cpp \ $(SRC_ROOT)/third_party/glslang/SPIRV/GlslangToSpv.cpp \ $(SRC_ROOT)/third_party/glslang/SPIRV/InReadableOrder.cpp \ $(SRC_ROOT)/third_party/glslang/SPIRV/Logger.cpp \ $(SRC_ROOT)/third_party/glslang/SPIRV/SpvBuilder.cpp \ $(SRC_ROOT)/third_party/glslang/SPIRV/SpvPostProcess.cpp \ $(SRC_ROOT)/third_party/glslang/SPIRV/SPVRemapper.cpp \ $(SRC_ROOT)/third_party/glslang/SPIRV/SpvTools.cpp \ $(SRC_ROOT)/third_party/jsoncpp/jsoncpp.cpp \ $(SRC_ROOT)/third_party/spirv-reflect/spirv_reflect.c \ $(SRC_ROOT)/third_party/stb/stb_image.c \ $(SRC_ROOT)/third_party/texture_compressor/dxt_encoder_internals.cc \ $(SRC_ROOT)/third_party/texture_compressor/dxt_encoder.cc \ $(SRC_ROOT)/third_party/texture_compressor/texture_compressor_etc1.cc \ $(SRC_ROOT)/third_party/texture_compressor/texture_compressor.cc \ $(SRC_ROOT)/third_party/vma/vk_mem_alloc.cpp \ $(SRC_ROOT)/third_party/volk/volk.c $(BUILD_DIR)/third_party/%.o: $(SRC_ROOT)/third_party/%.c @mkdir -p $(@D) $(HUSH_COMPILE) $(CC) -c $(THIRD_PARTY_CFLAGS) -o $@ $< $(BUILD_DIR)/third_party/%.o: $(SRC_ROOT)/third_party/%.cc @mkdir -p $(@D) $(HUSH_COMPILE) $(CXX) -c $(THIRD_PARTY_CXXFLAGS) -o $@ $< $(BUILD_DIR)/third_party/%.o: $(SRC_ROOT)/third_party/%.cpp @mkdir -p $(@D) $(HUSH_COMPILE) $(CXX) -c $(THIRD_PARTY_CXXFLAGS) -o $@ $< THIRD_PARTY_LIB := $(BUILD_DIR)/libthirdparty.a THIRD_PARTY_OBJS := $(call objs_from_src, $(THIRD_PARTY_SRC)) LIBS += $(THIRD_PARTY_LIB) OBJS += $(THIRD_PARTY_OBJS) $(THIRD_PARTY_LIB): $(THIRD_PARTY_OBJS) # --- demo application --- ifneq ($(filter demo,$(APPS)),) DEMO_SRC := \ $(SRC_ROOT)/demo/credits.cc \ $(SRC_ROOT)/demo/demo.cc \ $(SRC_ROOT)/demo/enemy.cc \ $(SRC_ROOT)/demo/hud.cc \ $(SRC_ROOT)/demo/menu.cc \ $(SRC_ROOT)/demo/player.cc \ $(SRC_ROOT)/demo/sky_quad.cc DEMO_EXE := $(call app_exe,demo) DEMO_OBJS := $(call objs_from_src, $(DEMO_SRC)) EXES += $(DEMO_EXE) OBJS += $(DEMO_OBJS) $(DEMO_EXE): $(DEMO_OBJS) $(LIBS) endif # --- Build rules --- # Dependencies. DEPS = $(OBJS:.o=.d) -include $(DEPS) .PHONY: all clean cleanall help all: $(EXES) clean: @echo "Cleaning..." $(HUSH_CLEAN) $(RM) -r $(BUILD_DIR) cleanall: @echo "Cleaning all..." $(HUSH_CLEAN) $(RM) -r $(INTERMEDIATE_DIR) help: @echo "BUILD = Build mode. One of:" @echo " debug (no optimizations)" @echo " release (optimizations, the default)" @echo "APPS = Applications to build. Defaults to all." @echo "VERBOSE = Full output from commands if set." # It's important that libraries are specified last as Ubuntu uses "ld --as-needed" by default. # Only the static libraries referenced by the object files will be linked into the executable. # Beware that circular dependencies doesn't work with this flag. $(EXES): @mkdir -p $(@D) $(HUSH_LINK) $(CXX) -o $@ $^ $(LDFLAGS) $(BUILD_DIR)/%.a: @mkdir -p $(@D) $(HUSH_GENERATE) $(AR) $(ARFLAGS) $@ $^ $(BUILD_DIR)/%.o: $(SRC_ROOT)/%.c @mkdir -p $(@D) $(HUSH_COMPILE) $(CC) -c $(CFLAGS) -o $@ $< $(BUILD_DIR)/%.o: $(SRC_ROOT)/%.cc @mkdir -p $(@D) $(HUSH_COMPILE) $(CXX) -c $(CXXFLAGS) -o $@ $< $(BUILD_DIR)/%.o: $(SRC_ROOT)/%.cpp @mkdir -p $(@D) $(HUSH_COMPILE) $(CXX) -c $(CXXFLAGS) -o $@ $<