Goal
Use concise makefile with organized directory structure. In particular, I don't want to have to edit the makefile to manage dependencies with every new source addition. The assumed directory structure is:
./src # Source files written by me (.cpp, .h) ./build # Build artifacts (*.o, *.d) ./include # Source files not written by me For now the ./include directory contains the header-only implementation of concurrentqueue.
I am using the following makefile.
# Compiler flags CXXFLAGS += -std=c++11 -Wall -Wextra -lpthread PREFLAGS := -MMD -MP # Executable TARGET := main # Source SRC := src INC := include # Build BUILD := build # Include directories INC_DIRS := $(INC) $(shell find $(SRC) -type d) INC_FLAGS := $(addprefix -I,$(INC_DIRS)) # Dependency/output filenames SRCS := $(shell find $(SRC) -name *.cpp) OBJS := $(subst $(SRC)/,$(BUILD)/,$(addsuffix .o,$(basename $(SRCS)))) DEPS := $(OBJS:.o=.d) $(TARGET): $(OBJS) $(CXX) $(OBJS) -o $@ $(BUILD)/%.o: $(SRC)/%.cpp mkdir -p $(dir $@) $(CXX) $(CXXFLAGS) $(PREFLAGS) $(INC_FLAGS) -c -o $@ $< -include $(DEPS) Issue
Everything was working fine until I tried to use the types from the concurrentqueue library. I created a simple header file with some typedefs.
// types.h #pragma once #include "message.h" #include "blockingconcurrentqueue.h" typedef moodycamel::BlockingConcurrentQueue<Message> message_queue_t; typedef moodycamel::BlockingConcurrentQueue<std::pair<uint32_t, Message>> tagged_message_queue_t; and then tried to instantiate the queues in my main.cpp,
message_queue_t send_queue; tagged_message_queue_t receive_queue; which resulted in the following linker errors on the final compilation step:
mkdir -p build/ g++ -std=c++11 -Wall -Wextra -lpthread -MMD -MP -Iinclude -Isrc -c -o build/main.o src/main.cpp g++ build/main.o build/protocol.o build/args.o build/config.o build/message.o build/util.o -o main build/main.o: In function `moodycamel::details::Semaphore::Semaphore(int)': main.cpp:(.text._ZN10moodycamel7details9SemaphoreC2Ei[_ZN10moodycamel7details9SemaphoreC5Ei]+0x3e): undefined reference to `sem_init' build/main.o: In function `moodycamel::details::Semaphore::~Semaphore()': main.cpp:(.text._ZN10moodycamel7details9SemaphoreD2Ev[_ZN10moodycamel7details9SemaphoreD5Ev]+0x14): undefined reference to `sem_destroy' collect2: error: ld returned 1 exit status make: *** [main] Error 1 What I've Tried
I have completed another project that used this same concurrentqueue library and had no issues. However, on that project, I wrote specific makefile targets for each *.cpp file, which required me to manage the dependencies myself. From my understanding, I should not have to do that. The only other differences between the previous project and this one I can think of is that
- There was no
./builddirectory. All build artifacts were placed in./src - There was no
./includedirectory. Theconcurrentqueuesrc files were placed in./src.
I'm at a loss for what the important difference is between my projects. For a sanity check, I tried getting rid of the ./include directory and placing the concurrentqueue header files back in ./src, but that led to the same linker errors.
sem_initetc. Try linking with thepthreadlibrary (-lpthread).