0

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 ./build directory. All build artifacts were placed in ./src
  • There was no ./include directory. The concurrentqueue src 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.

2

1 Answer 1

3

My final compilation step was not linking to -lpthread, which was why it was failing. Adding $(CXXFLAGS) to the main target resolved the issue.

$(TARGET): $(OBJS)
        $(CXX) $(CXXFLAGS) $(OBJS) -o $@
Sign up to request clarification or add additional context in comments.

3 Comments

With g++ (or gcc) you should turn on pthreads support with the -pthread option, at both compile time and link time, instead of explicitly linking libpthread (-lpthread). Especially so now that glibc is moving away from providing libpthread as a separate library.
Originally, the g++ i was using did not understand the -pthread option. However, it looks like my school updated g++ to a newer version, so I will make the change immediately.
Gcc/g++ has accepted -pthread for decades. If your version did not then you are stuck in the last century and you really need to upgrade.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.