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).