0

I am learning makefile and trying to write a general-purpose makefile for c/c++. The file structure I am targetting is as follow:

 |root
    | Makefile
    | inc
      |- commmon.hpp
      |- sourcelib
        |-coolthing.hpp (#include <common.hpp>)
    | src
      |- main.cpp (#include <sourcelib/coolthing.hpp>)
      |- sourcelib
        |-coolthing.cpp (#include <sourcelib/coolthing.hpp>)

This is what I currently have:

IDIR=inc
SRCIR=src
BIN=name

CC=g++
CFLAGS=-I $(IDIR) # specify where to find the headfiels

DEPS=$(shell find ./$(IDIR) -name "*.hpp") #find all the header files
CSRCS=$(shell find ./$(SRCIR) -name "*.c") #find all the .c file
CPPSRCS=$(shell find ./$(SRCIR) -name "*.cpp") #find all the .cpp file

COBJ=$(CSRCS:.c=.o)
CPPOBJ=$(CPPSRCS:.cpp=.o)

all: $(BIN)

%.o: %.cpp $(DEPS)
    ${CC} -c $^ $(CFLAGS)

%.o: %.c $(DEPS)
    ${CC} -c $^ $(CFLAGS)

$(BIN): $(COBJ) $(CPPOBJ)
    OBJ=$(shell find . -name "*.o") # find all the object file in the directroy of this Makefile
    $(CC) -o $@ $(OBJ)

The compiler can successfully create the object file of the source codes. However, when it tries to link the .o files, the compiler throws this error.

 g++ -c src/main.cpp inc/common.hpp inc/sourcelib/coolthing.hpp -I inc
 g++ -c src/sourcelib/coolthing.cpp inc/common.hpp inc/sourcelib/coolthing.hpp -I inc
 OBJ=./coolthing.o ./main.o  
 /bin/sh: 1: ./main.o: Exec format error   Makefile:24: recipe for
 target 'name' failed   make: *** [name] Error 2

Can someone tell me how to fix this problem? I am a noob to makefile. Thank you so much!

MadScientist
  • 92,819
  • 9
  • 109
  • 136
  • If linking fails, there should be an error from the linker. – chris Mar 24 '20 at 16:19
  • Note that the line `OBJ=$(shell find . -name "*.o")` is not valid shell syntax. – G.M. Mar 24 '20 at 16:52
  • Does this answer your question? [makefile : How to link object files from different subdirectory and include different search paths](https://stackoverflow.com/questions/28153873/makefile-how-to-link-object-files-from-different-subdirectory-and-include-diff) – Duck Dodgers Mar 24 '20 at 16:54
  • Each line of a recipe runs in its own subshell. You define OBJ in one line, but it dies with that line. In the next line, `OBJ` has no value, you try to execute `g++ -o name` and the linker throws its hands up. I suggest `$(CC) -o $@ $^` – Beta Mar 24 '20 at 17:02
  • Trying to write a "general-purpose makefile" is a fool's errand. The a large part of the point of `make` and makefiles is to capture *project-specific* build details in an actionable form. Some modern `make` implementations are nevertheless featureful enough to take a stab at the problem you have chosen, but the limitations are legion, starting with "The file structure I am targetting is [...]". Other issues will arise with projects that have external library dependencies. – John Bollinger Mar 26 '20 at 12:54
  • Also, C and C++ are distinct languages. Compiling C with a C++ compiler is incorrect. It may fail outright, and if it does not fail then the result may not behave as it would if compiled by a *bona fide* C compiler. – John Bollinger Mar 26 '20 at 13:00

1 Answers1

1

It does not fail on the linking. It does not even reach the linking line. It fails on this statement:

OBJ=./coolthing.o ./main.o 

This line is interpreted by shell as follows:

  • set OBJ variable to ./coolthing.o
  • execute ./main.o command

Since an object file cannot be executed directly, an error message is logged:

./main.o: Exec format error

If all you need is to get a list of objects to link, you should make use of your prerequisites and just use $^ instead of $(OBJ) in your linking statement and remove this OBJ generation line.

raspy
  • 3,995
  • 1
  • 14
  • 18