1

I have the following folder structure:

├── build
├── external
│   ├── build
│   ├── lib1
│   │   ├── lib1Classes.cc
│   │   └── lib1Classes.h
│   ├── lib2
│   │   ├── lib2Classes.cc
│   │   └── lib2Classes.h
│   ├── lib3
│   │   ├── lib3Classes.cc
│   │   └── lib3Classes.h
│   └── Makefile
├── include
│   ├── SomeClass.h
│   └── SomeOtherClass.h
├── Makefile
└── src
    ├── main.cpp
    ├── SomeClass.cc
    └── SomeOtherClass.cc

I am trying to first compile libXClasses.cc and libXClasses.h into ./external/build/libX.o, then combine all libX.o into an ./external/build/external.so. In step 2 I'd like to compile SomeClass.h and SomeClass.cc into ./build/SomeClass.o and SomeOtherClass.h, SomeOtherClass.cc into ./build/SomeOtherClass.o. Finally I want to link ./external/build/external.o and ./build/*.o into a binary in ./build.

I am however already failing in step 1. My idea for ./external/Makefile was something like this:

CXX = g++ -std=c++11

TARGET ?= external.so
BUILD_DIR ?= ./build

# get all source files
SRCS = $(shell find . -name *.cc -or -name *.cpp -or -name *.h)
# get the name of all directories that contain at least one source file
SRC_DIRS ?= $(foreach src,$(SRCS),$(shell dirname $(src)))
# remove duplicate directories
SRC_DIRS := $(shell echo $(SRC_DIRS) | xargs -n1 | sort -u | xargs)
# define one target object file foreach .cc source file
OBJS := $(foreach srcd,$(SRC_DIRS),$(BUILD_DIR)/$(patsubst %.cc,%.o,$(shell find $(srcd) -name *.cc -printf "%f\n")))

# rule to build ./external/build/external.so
$(BUILD_DIR)/$(TARGET): $(OBJS)
    $(CXX) -shared $(OBJS) -o $@

# no idea how to build libX.o in one rule
$(BUILD_DIR)/%.o: %.cc %.h
    $(CXX) -c -fpic $< -o $@

This does not work as in the last rule I am not specifying where the correct .cc and .h come from. But I don't know how I could do that at all. Do I have to write a rule for each libX directory separately? What if I have 10 or 20 libX directories?

Cheers!

Lxndr
  • 191
  • 1
  • 4
  • 13
  • What step, specifically does not work? – Anon Mail Sep 22 '17 at 14:24
  • Building the libX.o files in ./external/build.. I just don't know how to tell make to combine the following rules into one: ` build/lib1.o: lib1/lib1Classes.cc lib1/lib1Classes.h $(CXX) -c -fpic $< -o $@ build/lib2.o: lib2/lib2Classes.cc lib2/lib2Classes.h $(CXX) -c -fpic $< -o $@ build/lib3.o: lib3/lib3Classes.cc lib3/lib3Classes.h $(CXX) -c -fpic $< -o $@ ` – Lxndr Sep 22 '17 at 14:29
  • One solution is to put your *.o files in a common output directory regardless of where it's source file comes from. – Anon Mail Sep 22 '17 at 14:41
  • I am already trying to do that. The common output directory is external/build or am I misunderstanding something? – Lxndr Sep 22 '17 at 14:45
  • (_It's a long time since I played with Makefiles, so there may be new bits I don't know about, but..._) You should be able to make a generic "build libX.o" rule (and what you've got _may_ be it), but I _think_ you have to list `lib1.o`, `lib2.o` etc. as explicit dependencies of _something_ (probably `external.so`) so it knows the list of things it needs to apply that generic rule to. – TripeHound Sep 22 '17 at 15:08
  • My first rule should do that right? I mean it basically says: build/external.so: build/lib1.o build/lib2.o build/lib3.o but I think in the second rule make doesn't know which .cc and .h files to take so it doesn't execute the second rule. – Lxndr Sep 22 '17 at 15:23
  • You can have a look at [this answer](https://stackoverflow.com/questions/39015453/building-c-program-out-of-source-tree-with-gnu-make/39033569#39033569), with a few modifications you should be able to get what you want. – Tim Sep 25 '17 at 11:40

1 Answers1

0

Step 1: create a list of the libX directories (because no one wants to maintain a list like that by hand):

LIBS := $(wildcard external/lib*)

Step 2: create a list of the source files:

LIB_SRCS := $(notdir $(wildcard $(addsuffix /*.cc, $(LIBS))))

(I've removed the paths because they're a pain; there's more than one way to do this.)

Step 3: create a list of desired object files:

OBJS := $(patsubst lib%Classes.cc, external/build/lib%.o, $(LIB_SRCS))

Step 4: write a rule to build these files:

vpath %.cc $(LIBS)

$(OBJS): external/build/lib%.o: lib%Classes.cc
    $(CXX) -c -fPIC -I$(dir $<) $< -o $@

(Step 5: write a rule to build the library, but you already have that.)

One could do more. This makefile does not detect the fact that libN.o depends on libNClasses.h. It is possible to set that up, but it's a little complicated, and this is enough for one day.

Beta
  • 96,650
  • 16
  • 149
  • 150
  • Thanks, this works. But since this still does not cover the dependence on the header files I decided to switch to CMake. – Lxndr Sep 25 '17 at 10:47