I'm just learning GNU make, but I'm having trouble linking when using .d (dependency) files. Can anyone point me in the right direction with this error:
...../part1.o: file not recognized: File truncated
recipe for target 'bin/target/prog' failed
It's a simple program containing: main.cpp, part1.cpp, part1.h, part2.cpp, part2.h
Where part1 and part2 have a method to print something.
This is from terminal when running make:
I don't get why I'm getting a warning for using #pragma once?
stud#GoldenImageASE:~/Desktop/ISU/L1/2$ make ARCH=target -f Makefile.th
Compiling...part2.cpp
arm-devkit-g++ -MTbuild/target/part2.o -MM -I. part2.cpp > build/target/part2.d
Compiling...part1.cpp
arm-devkit-g++ -MTbuild/target/part1.o -MM -I. part1.cpp > build/target/part1.d
Compiling...main.cpp
arm-devkit-g++ -MTbuild/target/main.o -MM -I. main.cpp > build/target/main.d
object file....main.o
arm-devkit-g++ -I. -c main.cpp part1.h part2.h > build/target/main.o
part1.h:1:9: warning: #pragma once in main file
#pragma once
^
part2.h:1:9: warning: #pragma once in main file
#pragma once
^
object file....part1.o
arm-devkit-g++ -I. -c part1.cpp > build/target/part1.o
object file....part2.o
arm-devkit-g++ -I. -c part2.cpp > build/target/part2.o
arm-devkit-g++ -I. -o build/target/main.o build/target/part1.o build/target/part2.o -o prog
build/target/part1.o: file not recognized: File truncated
collect2: error: ld returned 1 exit status
Makefile.th:27: recipe for target 'bin/target/prog' failed
make: *** [bin/target/prog] Error 1
My Makefile is found below:
# Variables
SOURCES=main.cpp part1.cpp part2.cpp
OBJECTS=$(SOURCES:.cpp=.o)
DEPS=$(SOURCES:.cpp=.d)
EXE=prog
CXXFLAGS =-I.
# Making for host
# > make ARCH=host
ifeq (${ARCH},host)
CXX=g++
BUILD_DIR=build/host
EXE_DIR=bin/host
endif
# Making for target
# > make ARCH= target
ifeq (${ARCH},target)
CXX=arm-devkit-g++
BUILD_DIR=build/target
EXE_DIR=bin/target
endif
$(addprefix ${EXE_DIR}/,$(EXE)): $(addprefix ${BUILD_DIR}/,$(DEPS)) $(addprefix ${BUILD_DIR}/,$(OBJECTS))
# << Check the $(DEPS) new dependency
#mkdir -p $(dir $#)
$(CXX) $(CXXFLAGS) -o $(addprefix ${BUILD_DIR}/,$(OBJECTS))
$(addprefix $(BUILD_DIR)/, %.o): %.cpp
#echo "object file...."$*.o
$(CXX) $(CXXFLAGS) -c $^ > $#
# Rule that describes how a .d ( dependency ) file is created from a .cpp
# Similar to the assigment %. cpp -> %.o
${BUILD_DIR}/%.d: %.cpp
#mkdir -p $(dir $#)
#echo "Compiling..."$<
$(CXX) -MT$(#:.d=.o) -MM $(CXXFLAGS) $^ > $#
debug:
#echo "DEPS: "$(DEPS)"\n"
#echo "OBJ: " $(addprefix ${BUILD_DIR}/,$(OBJECTS))"\n"
#echo "EXE: " $(addprefix ${EXE_DIR}/,$(EXE))"\n"
.PHONY:clean
clean:
rm -f $(EXE) $(addprefix ${BUILD_DIR}/,$(DEPS)) $(addprefix ${BUILD_DIR}/,$(OBJECTS))
ifneq ($(MAKECMDGOALS),clean)
-include $(addprefix ${BUILD_DIR}/,$(DEPS))
endif
You have two unrelated problems. The first one is that you have two conflicting -o options when linking.
The actual problem you ask about is something different, but still related to the -o option: Namely that you don't have one when attempting to create the object files.
When creating the object files, the generated object file is not written to standard output, therefore your redirection will not cause the gcc frontend program to create an object file with the name you think.
For example:
arm-devkit-g++ -I. -c part1.cpp > build/target/part1.o
The above command will create an object file named part1.o in the current directory, and write the (empty) standard output to the file build/target/part1.o. That will leave build/target/part1.o empty, which is what the linker is complaining about (that's what it means when it says the file is truncated).
The command should instead look like
arm-devkit-g++ -I. -c part1.cpp -o build/target/part1.o
Note the use of the -o option to name the output file.
You need to modify the makefile to not use redirection when building the object files.
Also, you should not list the header files when building object files, only the source file you want to build, so the command
arm-devkit-g++ -I. -c main.cpp part1.h part2.h > build/target/main.o
should really be
arm-devkit-g++ -I. -c main.cpp -o build/target/main.o
You're not compiling your object files correctly. g++ doesn't output the files to stdout, it writes them to the local directly. If you want to put the object files in a specific directory, you need to use the -o option:
$(BUILD_DIR)/%.o: %.cpp | $(BUILD_DIR)
$(CXX) $(CXXFLAGS) -c $^ -o $#
^^^^^^
$(BUILD_DIR):
#mkdir -p $#
Also you're building your executable incorrectly. The dependencies are insufficient and you don't have your target listed. You'll want this:
$(EXE_DIR)/$(EXE) : $(addprefix $(BUILD_DIR),$(OBJECTS)) | $(EXE_DIR)
$(CXX) $(CXXFLAGS) -o $# $^
$(EXE_DIR):
#mkdir -p $#
This will create an order-only dependency from your binary on the directory, and correctly build the binary. Note that you shouldn't have a dependency from your target on your .d files. That makes little sense. Instead, your rule for building the .os should simply also build the .ds (that rule suffers the same problem currently as your .o rule):
# build the .o and the .d in one go
$(BUILD_DIR)/%.o : %.cpp | $(BUILD_DIR)
$(CXX) $(CXXFLAGS) -o $# -c $< -MP -MMD -MF $(#:.o=.d)
AS AN EDITORIAL ASIDE, THERE IS THIS COMMON TENDENCY TO WRITE ALL VARIABLES IN MAKEFILES IN SHOUTY_CAPS. THIS IS PROVABLY MUCH MORE DIFFICULT TO READ THAN USING JUST USING snake_case. Lower case letters work just fine.
Related
I am quite new to Make. I am attempting to write a Makefile to build a medium-sized Linux C/C++ application as below.
Making a simple Makefile by having all source files in one location and explicitly listing the source files works ok for me but I would like it to be more generic.
I have all my source files (C and C++) in the src folder in different subdirectories. I have header files inside an inc and inc/common folder, and then libs inside a lib folder.
The Makefile is run on the same level :
SRC_DIR := src
OBJ_DIR := obj
BIN_DIR := bin
CXX := /bin/arm-linux-gnueabi-g++
EXE := $(BIN_DIR)/runfile
SRC := $(shell find $(SRC_DIR) -name *.cpp -or -name *.c)
OBJ := $(patsubst $(SRC_DIR)/%,$(OBJ_DIR)/%,$(addsuffix .o,$(basename $(SRC))))
CPPFLAGS := -Iinc -Iinc/common -MMD -MP
CXXFLAGS := -std=c++11 -Wall
LDFLAGS := -Llib
LDLIBS :=
.PHONY: all clean
all: $(EXE)
$(EXE): $(OBJ) | $(BIN_DIR)
$(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $#
$(OBJ_DIR)/%.o: $(SRC) | $(OBJ_DIR)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $#
$(BIN_DIR) $(OBJ_DIR):
mkdir -p $#
clean:
#$(RM) -rv $(BIN_DIR) $(OBJ_DIR)
-include $(OBJ:.o=.d)
I get lots of errors such as below when I run it, including problems opening dependency files. I think i'm almost there, but can't see my error exactly :
compilation terminated.
/bin/arm-linux-gnueabi-g++ -Iinc -Iinc/common -MMD -MP -std=c++11 -Wall -c -o obj/main.d.o
cc -Llib obj/main.d.o -o obj/main.d
/usr/bin/ld: obj/main.d.o: relocations in generic ELF (EM: 40)
/usr/bin/ld: obj/main.d.o: relocations in generic ELF (EM: 40)
/usr/bin/ld: obj/main.d.o: error adding symbols: file in wrong format
I don't see how the output you show can be generated from the makefile you show here but anyway.
This is not right:
$(OBJ_DIR)/%.o: $(SRC) | $(OBJ_DIR)
A pattern rule is a template that tells make "if you want to build a target that matches this pattern, then you can build it from the prerequisites that match this pattern".
Here you are listing ALL your source files as a prerequisite for EVERY object file. Suppose SRC is set to foo.c bar.c biz.c baz.c, then this expands to:
obj/%.o : foo.c bar.c biz.c baz.c | obj
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $#
You're telling make that every single .o target depends on ALL the source files, not just the one for that object file. Further, the automatic variable $< always expands to the first prerequisite, which here will always be foo.c. So, you're compiling foo.c four times, creating each of the object files.
The very first important rule when debugging makefiles is to look carefully at the output (command lines) that make prints. If they are not right, then your makefile is not right. If you do that you'll see all the compile lines are compiling the same source, like:
g++ -c foo.c -o obj/foo.o
g++ -c foo.c -o obj/bar.o
g++ -c foo.c -o obj/biz.o
g++ -c foo.c -o obj/baz.o
That clearly cannot work and it's why you get link errors trying to link together all these object files: they all have the same content.
You need this:
$(OBJ_DIR)/%.o : $(SRC_DIR)/%.cpp
#mkdir -p $(#D)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $#
which tells make how to build an object file from a single source file.
You also need to create the actual output directory that the object file will go into. Just creating $(OBJ_DIR) is not enough, if the object file appears in a subdirectory.
It's possible to compile a list of .cpp with make ?
In my makefile i have 2 lists, one of .o and the second is for .cpp.
The list of the .o is the same of .cpp with different path.
I can't use vpath because i have multiple .cpp with same names.
I can browse the .o but not the .cpp:
$(OBJS): $(SRC)
$(LINKER) -g -o $# $^ $(LDFLAGS)
In this case, my .cpp is the same for all .o.
$(OBJS) is the list of .o and $(SRC) the .cpp
Example of Makefile:
COMPILATEUR=g++
LINKER=g++
LDFLAGS=
CFLAGS=-Og
PATH_BUILD=$(pwd)/Build/
EXE=Bidou
INCLUDES= -I"AAA/BBB" \
-I"AAA/BBB/CC/dd"
SRC= AAA/BBB/CC/dd.cpp \
AAA/BBB/hh.cpp \
AAA/BBB/CC/dd/ee.cpp \
AAA/BBB/cc.cpp
OBJS:= $(addprefix $(PATH_BUILD)/,$(notdir $(SRC:%.cpp=%.o)))
$(OBJS): $(SRC)
#mkdir -p $(PATH_BUILD)
#echo "\n##$<"
$(COMPILATEUR) $(INCLUDES) $(CFLAGS) "$<" -g -c -o $#
$(EXE): $(OBJS)
$(LINKER) -g -o $# $^ $(LDFLAGS)
clean:
rm -fr $(PATH_BUILD)
That rule is... really wrong. The target(s) are object files, but the recipe you're using is a link command that generates an executable, not compile command that generates an object file.
There's really not much we can do to help you unless we know the contents of the SRC and OBJS variables.
If, for example, it's a fact that all the object files have identical paths to the source files just with the extension changed from .cpp to .o, then you don't even need to define a rule to build those object files: make has a rule that will do that built in; you can just write:
program: $(OBJS)
$(LINKER) -g -o $# $^ $(LDFLAGS)
(if the name of the program you wanted to create from the object files is program).
ETA
If there's no algorithmic way to reliably convert from an object file name to a single known source file, then there's no way you can write a pattern rule that will do the job.
That means you'll have to write out all the dependency relationships by hand. You can do something like this:
$(OBJS) :
#mkdir -p $(#D)
#echo "\n##$<"
$(COMPILATEUR) $(INCLUDES) $(CFLAGS) "$<" -g -c -o $#
$(for S,$(SRCS),$(eval $(PATH_BUILD)/$(notdir $(S:%.cpp=%.o)): $S))
This creates a way to build each object file, then writes a separate set of dependencies for each .o file depending on its related .c file.
I have a project that I want to build a shared library for it. The following Makefile works:
libfastpd.so: fastpd.cpp
$(CXX) -std=c++11 -fPIC -c fastpd.cpp -o fastpd.o
$(CXX) -std=c++11 -fPIC -c graph.cpp -o graph.o
$(CXX) -std=c++11 -fPIC -c LinkedBlockList.cpp -o LinkedBlockList.o
$(CXX) -std=c++11 -fPIC -c maxflow.cpp -o maxflow.o
$(CXX) -std=c++11 -shared -Wl,-soname,libfastpd.so -o libfastpd.so fastpd.o graph.o LinkedBlockList.o maxflow.o
clean:
rm *.o *.so
Then I came across this recipe in Cogswell et al.'s C++ Cookbook: https://www.oreilly.com/library/view/c-cookbook/0596007612/ch01s18.html
and decided to improve my Makefile based on that:
# Specify extensions of files to delete when cleaning
CLEANEXTS = o so
# Specify the source files, the target files,
# and the install directory
SOURCES = fastpd.cpp graph.cpp LinkedBlockList.cpp maxflow.cpp
OUTPUTFILE = libfastpd.so
INSTALLDIR = ./
.PHONY: all
all: $(OUTPUTFILE)
# Build lib*.so from all the *.o;
# subst is the search-and-replace
# function demonstrated in Recipe 1.16
$(OUTPUTFILE): $(subst .cpp,.o,$(SOURCES))
$(CXX) -shared -fPIC $(LDFLAGS) -o $# $^
.PHONY: install
install:
mkdir -p $(INSTALLDIR)
cp -p $(OUTPUTFILE) $(INSTALLDIR)
.PHONY: clean
clean:
for file in $(CLEANEXTS); do rm -f *.$$file; done
# Generate dependencies of .ccp files on .hpp files
include $(subst .cpp,.d,$(SOURCES))
%.d: %.cpp
$(CC) -M $(CPPFLAGS) $< > $#.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $# : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$
Running this file I obtained the following error:
/usr/bin/ld: fastpd.o: relocation R_X86_64_32 against `.rodata' can
not be used when making a shared object; recompile with -fPIC
fastpd.o: error adding symbols: Bad value
Checking the terminal output, I observed that the following commands were executed:
g++ -c -o fastpd.o fastpd.cpp
g++ -c -o graph.o graph.cpp
g++ -c -o LinkedBlockList.o LinkedBlockList.cpp
g++ -c -o maxflow.o maxflow.cpp
No -fPIC!
My question is: Which lines of the Makefile execute these commands and how to add -fPIC to them?
Any references to good ressources to understand the entire Makefile above would be very much appreciated as well!
Thank you very much in advance for your help!
Which lines of the Makefile execute these commands... ?
The short answer is none. The rule...
$(OUTPUTFILE): $(subst .cpp,.o,$(SOURCES))
$(CXX) -shared -fPIC $(LDFLAGS) -o $# $^
only specifies the link time dependencies and command. The -fPIC option needs to be specified when you compile the source file but you haven't provided any rule to build a .o from a .cpp so make falls back on its implicit rule which (for the purposes of this example) is essentially...
%.o: %.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $<
So the obvious solution is to add -fPIC to CXXFLAGS...
CXXFLAGS += -fPIC
I want my object files to be created in a subdirectory and not where Makefile lives. So, I saw this answer, which I couldn't apply to my case, so I tried this:
OBJS = main.o IO.o alloc.o communication.o
OBJSDIR = obj
SOURCE = main.cpp src/IO.cpp src/alloc.cpp src/communication.cpp
HEADER = headers/IO.h headers/alloc.h headers/communication.h
OUT = test
CXX = ../../mpich-install/bin/mpic++
CXXFLAGS = -I../../intel/mkl/include -Wl,--start-group -Wl,--end-group -lpthread -lm -ldl -Wall
LDFLAGS = ../../intel/mkl/lib/intel64/libmkl_scalapack_lp64.a -Wl,--start-group ../../intel/mkl/lib/intel64/libmkl_intel_lp64.a ../../intel/mkl/lib/intel64/libmkl_core.a ../../intel/mkl/lib/intel64/libmkl_sequential.a -Wl,--end-group ../../intel/mkl/lib/intel64/libmkl_blacs_intelmpi_lp64.a -lpthread -lm -ldl
all: $(OBJSDIR) $(OUT)
$(OBJSDIR):
mkdir $(OBJSDIR)
$(OUT): $(OBJS)
$(CXX) $(OBJS) -o $(OUT) $(CXXFLAGS) $(LDFLAGS)
# make -f Makefile clean
# create/compile the individual files >>separately<<
$(OBJSDIR)/main.o: main.cpp
$(CXX) -c main.cpp $(CXXFLAGS)
$(OBJSDIR)/IO.o: src/IO.cpp
$(CXX) -c src/IO.cpp $(CXXFLAGS)
$(OBJSDIR)/alloc.o: src/alloc.cpp
$(CXX) -c src/alloc.cpp $(CXXFLAGS)
$(OBJSDIR)/communication.o: src/communication.cpp
$(CXX) -c src/communication.cpp $(CXXFLAGS)
.PHONY: clean
clean:
rm -rf *.o
and I am getting:
gsamaras#pythagoras:~/konstantis/cholesky$ make
../../mpich-install/bin/mpic++ -I../../intel/mkl/include -Wl,--start-group -Wl,--end-group -lpthread -lm -ldl -Wall -c -o main.o main.cpp
make: *** No rule to make target 'IO.o', needed by 'test'. Stop.
I have a src folder, where all the .cpp files live (except from main.cpp, that lives in the same directory as the Makefile) and a headers directory, where all the header files live.
EDIT
I modified the first two lines, as such:
OBJSDIR = obj
OBJS = $(OBJSDIR)/main.o $(OBJSDIR)/IO.o $(OBJSDIR)/alloc.o $(OBJSDIR)/communication.o
and I am getting:
g++: error: obj/main.o: No such file or directory
...
The problem lies into the fact that the object files are still generated in the main directory!
You want to change the lines that invoke your compiler from:
$(OBJSDIR)/IO.o: src/IO.cpp
$(CXX) -c src/IO.cpp $(CXXFLAGS)
to:
$(OBJSDIR)/IO.o: src/IO.cpp
$(CXX) -c src/IO.cpp $(CXXFLAGS) -o $#
Note that $# is the automatic variable that corresponds to the target file being created. So in the above case it will be obj/IO.o. -o specifies the output filename.
Furthermore while it is unrelated to your question one of the nice things about placing all the build artifacts into a separate directory is cleaning is much easier:
clean:
rm -rf $(OBJSDIR) $(OUT)
Also, as a final note if you ever wish to do a parallel build you will have an issue as your object files rely on the build directory. There are a couple solutions to this including calling mkdir -p objs before every compiler invocation or setting up the directory as a dependency that is only built if it does not exist.
I have written a simple C++ program, and for the first time I want to compile and link it using a makefile. As a challenge I want to make a makefile, which lists all dependencies by itself. I am following this tutorial. My program consist of main.cpp, ext1.cpp and ext1.h. Following the tutorial, I have the following makefile
VPATH = src include
CPPFLAGS = -o include
CC = gcc
SOURCES = main.cpp \
ext1.cpp
-include $(subst .c,.d,$(SOURCES))
%.d: %.c
$(CC) -M $(CPPFLAGS) $< > $#.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $# : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$
When I run this I get the message: make: *** No targets specified and no makefile found. Stop. It is not clear to me what I am missing in my case?
You are trying to do too much at once.
Step 1. Your first makefile should build the executable without attempting automatic dependency detection.
VPATH = include src
CPPFLAGS += -Iinclude
CC = gcc
exec: main.o ext1.o
$(CC) $^ -o $#
%.o: %.cc
$(CC) -c $(CPPFLAGS) $< -o $#
main.o ext1.o: ext1.h
Step 2. Once that works perfectly, you can put the header dependencies in separate files:
makefile:
VPATH = include src
CPPFLAGS += -Iinclude
CC = gcc
exec: main.o ext1.o
$(CC) $^ -o $#
%.o: %.cc
$(CC) -c $(CPPFLAGS) $< -o $#
-include *.d
main.d:
main.o : ext1.h
ext1.d:
ext1.o: ext1.h
Step 3. Once that works perfectly, you can generate the dependency files automatically:
VPATH = include src
CPPFLAGS += -Iinclude
CC = gcc
exec: main.o ext1.o
$(CC) $^ -o $#
%.o: %.cc
$(CC) -c -MMD $(CPPFLAGS) $< -o $#
-include *.d
no make file found ? what name you have given for makefile? make sure its makefile or Makefile if you are just executing command make else you can pass file name to make like this
make -f yourmakefile
and changes suggested by Petr Budnik must work