0

I am building a small utility library in c++, and I am adding some examples to it. The project structure looks like this:

MyLib
  |__bin
  |
  |__include
  |  |__mylib.hpp
  |
  |__lib
  |
  |__examples
  |  |__example.cpp
  |
  |__src
  |  |__mylib.cpp
  |
  |__Makefile

Here is what my Makefile looks like:

LIBK = mylib
LIBS = $(LIBK).a

CXXFLAGS := -Wall -Wextra -std=c++17 -ggdb

BIN             := bin
SRC             := src
INCLUDE         := include
LIB             := lib
EXAMPLES        := examples

all: lib examples

lib: $(LIB)/$(LIBK)

examples: lib $(BIN)/$(EXAMPLES)

run: clean all
        clear
        ./$(LIB)/$(LIBK)

$(LIB)/$(LIBK): $(SRC)/*.cpp
        -mkdir -p lib
        $(CXX) -c $(CXXFLAGS) -I$(INCLUDE) -L$(LIB) $^ -o [email protected]
        ar rcs $(LIB)/lib$(LIBK).a [email protected]

$(BIN)/$(EXAMPLES): $(EXAMPLES)/*.cpp
        -mkdir -p bin
        $(CXX) $(CXXFLAGS) -I$(INCLUDE) -L$(LIB) -l$(LIBK) $^ -o $@ 
clean:
        -rm -rf $(BIN)/*
        -rm -rf $(LIB)/*

My problem is that everything seems to look fine when I run make, but it fails when I run make -j8 with the following error.

cannot find -lmylib
collect2: error: ld returned 1 exit status
make: *** [Makefile:36: bin/examples] Error 1
make: *** Waiting for unfinished jobs....
ar rcs lib/libmylib.a lib/mylib.o

It seems like the multiple core instruction triggers both compilations at the same time, without waiting for the library to build before launching the job to build the example. I believe I had defined the dependencies correctly, but there is something obviously wrong that I don't seem to be able to find by myself.

EDIT: Seeing that I the original Makefile is fundamentally incorrect, but no answer really provided an alternative one, I created a new one to the best of my knowledge that seems to work. Any constructive and respectful criticism is welcome.

LIBNAME         := libIntegration.a                                                                                                                                                                                                                            
  
CXX               := g++

BIN             := bin
SRC             := src
INCLUDE         := include
LIB             := lib

LIBRARIES       := -lIntegration
EXECUTABLE      := main

LIBRARY_SOURCES := $(SRC)/mxIntegration.o
EXECUTABLE_SOURCES := examples/main.o

CXXFLAGS := -Wall -Wextra -std=c++17 -ggdb -I$(INCLUDE)

all: $(BIN)/$(EXECUTABLE)

run: clean all
        clear
        ./$(BIN)/$(EXECUTABLE)

$(LIB)/$(LIBNAME): $(LIBRARY_SOURCES)
        ar rcs $@ $^

$(BIN)/$(EXECUTABLE): $(LIB)/$(LIBNAME)
        $(CXX) $(CXXFLAGS) -I$(INCLUDE) -L$(LIB) $(EXECUTABLE_SOURCES) -o $@ $(LIBRARIES)
clean:
        -rm -rf $(BIN)/*
        -rm -rf $(LIB)/*
2
  • Except for phony targets, the commands should create a file named exactly like the target. You have a target $(LIB)/$(LIBK) but the ar command creates a file $(LIB)/lib$(LIBK).a. This means the commands will always be executed even if no dependency has changed because the expected target file does not exist. Commented Sep 14, 2022 at 15:20
  • Hey, if you fixed the problem, you should post a (self-) answer rather than editing the original question. You should also point out what the problem in the original makefile was. Commented Sep 14, 2022 at 16:41

1 Answer 1

3

This is a super-bizarre makefile. I'm not sure why you even bother to use make at all, because you are always recompiling every source file whenever any source file changes.

But, just to deal with your specific question your error message says:

cannot find -lmylib

so clearly the example is being built before the library is done. So, let's look at the rule for building examples:

$(BIN)/$(EXAMPLES): $(EXAMPLES)/*.cpp

Here you list the source files as prerequisites of the target. But nowhere have you listed the library as a prerequisite. So, make has no idea that you need to wait for the library to be built, and you definitely haven't defined that dependency.

Sign up to request clarification or add additional context in comments.

4 Comments

I'm still trying to figure out what $(CXX) -c $(CXXFLAGS) -I$(INCLUDE) -L$(LIB) $^ -o [email protected] and ar rcs $(LIB)/lib$(LIBK).a [email protected] are actually going to do when fed multiple source files. Gut feel is they're fundamentally broken.
That works. That is the fundamental template provided by one of the main vscode extensions for makefile projects. I just run with it assuming it is not terribly wrong
@MarcosAlvarez What do you mean with "That works."? The Makefile is terribly wrong. It just happens to produce some expected results under certain preconditions.
@AndrewHenle yes that will give a compile error if you ever have multiple source files: gcc: fatal error: cannot specify ‘-o’ with ‘-c’, ‘-S’ or ‘-E’ with multiple files. There's so much "wrong" with this makefile that I just decided to answer the asked question rather than try to write a novel about it :p :).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.