0

I have found a lot of related questions, but I was still not able to make my own Makefile. This makefile is using Mingw64 on Windows, and I want it to run on *nix, currently Debian, but I would like to be able to make it run on Alpine too, as it's used in a Docker container.

The project tree structure is something like :

./
  src/
    main.cpp
    Server.cpp <- use asio and Utils/Split.h
    Server.h   <- use asio
    Utils/
      Split.h
  lib/
    asio/include/ <- asio library (without boost, header only)
  Makefile <- That is what I am trying to do right now
  Dockerfile

I tried multiple things, here is my latest Makefile (that obviously, does not work) :

NAME        := GameServer
CXX         := g++
CXXFLAGS    := -std=c++2a -DASIO_STANDALONE

SRC_DIR     := ./src
LIBS        := -I lib/asio-1.18.1/include \
               -I lib/rapidjson-1.1.0/include \
               -I src

rwildcard   = $(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2))

SRCS        := $(call rwildcard,$(SRC_DIR),*.cpp)
OBJS        := $(SRCS:%.cpp=%.o)

.PHONY: all

all: $(NAME)

$(NAME): $(OBJS)
    $(CXX) -o $@ $^

$(OBJS): $(SRCS)
    $(CXX) $(CXXFLAGS) -c -o $@ $< $(LIBS)

Note: the code (.cpp, .h) is valid, it's coming from an already-running project, but built on Visual Studio (compiled with MSVC).

Here are the two functions done my mingw32-make :

g++ -c -o src/Server.o src/main.cpp -I lib/asio/include -I src
g++ -o Server src/main.o src/Server.o

First line : It should builds the .o from the .cpp and adds the include to asio. I added -I src to add src/Utils, but I guess that's not the way of doing it ?
Second line : It should (link ?) the two .o in a single file : the executable.

The errors I am getting with this makefile are :

  • src/Server.o:main.cpp:(.text+0x36): multiple definition of 'main', src/main.o:main.cpp:(.text+0x36): first defined here (and this, for every .o)
  • src/main.o:main.cpp:(.text+0x4b): undefined reference to 'Server::Server()' (and this, for every Server methods main calls, even some from asio)
    They appears when the second g++ line starts (g++ -o Server src/main.o src/Server.o)

So here are my questions :

  1. What am I doing wrong ?
  2. Is there a better way of trying to make a development environment on Windows and still be able to copy the project in a Docker container (and then compile it with the gcc image) to build it with the same Makefile ?

Sorry if I forgot to mention some details, I am new with Mingw and its environment.

Thank you

Edit : Corrected version :

NAME        := GameServer
CXX         := g++
CXXFLAGS    := -std=c++1z

SRC_DIR     := ./src
LIBS        := -lwsock32 -lws2_32 \
               -I lib/asio-1.18.1/include \
               -I lib/rapidjson-1.1.0/include \
               -I src

rwildcard   = $(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2))

SRCS        := $(call rwildcard,$(SRC_DIR),*.cpp)
OBJS        := $(SRCS:%.cpp=%.o)

.PHONY: all

all: $(NAME)

$(NAME): $(OBJS)
    $(CXX) -o $@ $^ $(LIBS)

$(OBJS): $(SRC_DIR)/%.o: $(SRC_DIR)/%.cpp
    $(CXX) $(CXXFLAGS) -c -o $@ $< $(LIBS)
Lucas
  • 3
  • 2
  • 2
    `g++ -c -o src/Server.o src/main.cpp` This is done incorrectly causing the next line linking two object files of main.cpp. – 273K Jul 04 '21 at 15:40

1 Answers1

2

Consider the rule...

$(OBJS): $(SRCS)
    $(CXX) $(CXXFLAGS) -c -o $@ $< $(LIBS)

This tells make that all items in $(OBJS) depend on all items in $(SRCS). But the command...

$(CXX) $(CXXFLAGS) -c -o $@ $< $(LIBS)

...always compiles the first dependency as identified by $<. It just so happens that in your case $< is src/main.cpp.

Instead you should probably use a pattern rule such as...

$(SRC_DIR)/%.o: $(SRC_DIR)/%.cpp
    $(CXX) $(CXXFLAGS) -c -o $@ $< $(LIBS)

You can also limit the scope of that rule to only those targets specified by $(OBJS) with a full static pattern rule...

$(OBJS): $(SRC_DIR)/%.o: $(SRC_DIR)/%.cpp
    $(CXX) $(CXXFLAGS) -c -o $@ $< $(LIBS)
G.M.
  • 12,232
  • 2
  • 15
  • 18
  • Just for clarification, the first example is not a _static_ pattern rule, it's just a pattern rule. The second example is a static pattern rule. – MadScientist Jul 04 '21 at 17:01
  • Thanks, it fixed my issues, I still have one though : `./src/main.o:main.cpp:(.text$_ZN4asio6detail17winsock_init_base7startupERNS1_4dataEhh[_ZN4asio6detail17winsock_init_base7startupERNS1_4dataEhh]+0x7a): undefined reference to `__imp_WSAStartup'`. I am using standalone version of Asio, so am I missing something ? – Lucas Jul 04 '21 at 17:34
  • @MadScientist Indeed, edited and thanks for the correction. Let me know if it still needs 'work'. – G.M. Jul 04 '21 at 17:36
  • @Lucas Re. `undefined reference to __imp_WSAStartup` you might want to look at [this post](https://stackoverflow.com/questions/18559028/undefined-reference-to-imp-wsacleanup). – G.M. Jul 04 '21 at 17:38
  • Thanks, it fixed it, just added in LIB variable : -lwsock32 -lws2_32 – Lucas Jul 04 '21 at 17:47