I am trying to link a static library while creating my program executable using the below makefile..
IDIR =../inc
CC=g++ -g
CFLAGS=-I$(IDIR)
WFLAGS=-Wall -W
OFLAGS=-O3
DLINUX=-D_LINUX
ODIR=obj
LDIR =../lib
LIBS=-lm
_OBJ = testclient.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
$(ODIR)/testclient.o: testclient.c
$(CC) -c $< $(CFLAGS) -o $#
$(ODIR)/file2.o: file2.c
$(CC) -c $< $(CFLAGS) -o $#
testclient: $(OBJ)
$(CC) -o $# $^ $(LIBS) -lccn -pthread
.PHONY: clean
clean:
rm -f $(ODIR)/*.o *~ core $(INCDIR)/*~
I have tried everything available from changing the order of the '-lccn' parameter to checking whether the function exists in the library (nm libccn.a gives the required function ccn_create() in it). The error returned is :
obj/testclient.o: In function `main':
/root/testClient/src/testclient.c:91: undefined reference to `ccn_create()'
The library libccn.a is in /usr/local/lib. I have also tried changing the directory path and then using -L flag to look in that location. Doesn't work either. :( ..Any ideas as to how can i make it work ?
My guess is that libccn.a is a C library and the header that you use are not designed to be imported by a C++ compiler (there is no extern "C" { } block surrounding the function definition).
C++ supports function overloading by mangling name of function. When you put a function in a extern "C" { } block, C++ disable name mangling (and thus disable overloading). Here, in your error message, the function mentioned is ccn_create(). Notice the (), this means that the function type is known, and thus the named looked up was a mangled name.
When you do nm libccn.a you see the real name, and it is ccn_create. That is not a mangled name. So to fix this, you'll need to surround the function definition in a export "C" { } block. The easiest way to do that is to surround the #include in such a block.
BTW, you can reproduce the error by doing this.
$ echo 'void ccn_create();' > ccn.h
$ echo '#include "ccn.h"
void ccn_create() { }' > ccn.c
$ echo '#include "ccn.h"
int main () {
ccn_create();
return 0;
}' > main.cc
$ gcc -o ccn.o -c ccn.c
$ g++ -o main main.cc ccn.o
Undefined symbols for architecture x86_64:
"ccn_create()", referenced from:
_main in cc8XnYRq.o
ld: symbol(s) not found for architecture x86_64
$ echo 'extern "C" {
#include "ccn.h"
}
int main () {
ccn_create();
return 0;
}' > main.cc
$ g++ -o main main.cc ccn.o
Related
I am trying to follow and convert [this][1] Googletest tutorial to work in windows and use Make for building. I am also trying to add a more typical directory structure.
[1]: https://www.eriksmistad.no/getting-started-with-google-test-on-ubuntu/
My directory structure:
D:.
│ makefile
│
├───bin
├───inc
│ whattotest.h
│
├───obj
├───src
│ whattotest.cpp
│
└───tests
tests.cpp
whattotest.h
#pragma once
double squareRoot(const double a);
whattotest.cpp
#include <math.h>
#include "whattotest.h"
double squareRoot(const double a) {
double b = sqrt(a);
if(b != b) { // nan check
return -1.0;
}else{
return sqrt(a);
}
}
tests.cpp
#include "whattotest.h"
#include <gtest/gtest.h>
TEST(SquareRootTest, PositiveNos) {
ASSERT_EQ(6, squareRoot(36.0));
ASSERT_EQ(18.0, squareRoot(324.0));
ASSERT_EQ(25.4, squareRoot(645.16));
ASSERT_EQ(0, squareRoot(0.0));
}
TEST(SquareRootTest, NegativeNos) {
ASSERT_EQ(-1.0, squareRoot(-15.0));
ASSERT_EQ(-1.0, squareRoot(-0.2));
}
int main(int argc, char **argv) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
makefile
CXX = g++
OBJ = obj
SRC = src
TESTS = tests
INC = inc
BIN = bin
LIBS= -lpthread
GTEST=D:\myWorkspace\Gtest\googletest-release-1.11.0\googletest\include\
LIBGTEST=D:\myWorkspace\Gtest\googletest-release-1.11.0\lib\libgtest.a
.PHONY : all
all: $(BIN)/runTests
$(BIN)/runTests: $(OBJ)/tests.o $(OBJ)/whattotest.o $(LIBGTEST)
#g++ -o runTests obj/tests.o obj/whattotest.o <path to libgtest.a> -pthread
$(CXX) -o $# $^ $(LIBS)
$(OBJ)/tests.o: $(TESTS)/tests.cpp
#g++ -I <path to gtest> -I inc -c tests.cpp -o tests.o
$(CXX) -I $(GTEST) -I $(INC) -c $< -o $#
$(OBJ)/whattotest.o: $(SRC)/whattotest.cpp
$(CXX) -I $(INC) -c $< -o $#
clean:
-rm $(OBJ)/*.o
-rm $(BIN)/*.exe
When I run this I get the following error:
g++ -I D:\myWorkspace\Gtest\googletest-release-1.11.0\googletest\include LIBGTEST=D:\myWorkspace\Gtest\googletest-release-1.11.0\lib\libgtest.a -I inc -c tests/tests.cpp -o obj/tests.o
g++: warning: LIBGTEST=D:\myWorkspace\Gtest\googletest-release-1.11.0\lib\libgtest.a: linker input file unused because linking not done
g++: error: LIBGTEST=D:\myWorkspace\Gtest\googletest-release-1.11.0\lib\libgtest.a: linker input file not found: Invalid argument
make: *** [makefile:19: obj/tests.o] Error 1
The way I thought this would run would be for Make to see the Rule for runTests requires tests.o, which does not exist, then drop down and use the Rule for creating that object file. After that, return to the Rule for runTests and complete.
The output looks like Make is combining the two rules together into some kind of amalgamation with -c and .cpp files combined. Which I believe is causing this error to occur.
I am confused as to why Make is doing this.
Check this:
GTEST=D:\myWorkspace\Gtest\googletest-release-1.11.0\googletest\include\
LIBGTEST=D:\myWorkspace\Gtest\googletest-release-1.11.0\lib\libgtest.a
By having a backslash at the end of the GTEST variable assignment you've continued that line to the next line, so GTEST contains the variable assignment on the next line as well (and LIBGTEST is not set).
You've basically written this:
GTEST=D:\myWorkspace\Gtest\googletest-release-1.11.0\googletest\include LIBGTEST=D:\myWorkspace\Gtest\googletest-release-1.11.0\lib\libgtest.a
You should not, in general, use backslashes in makefiles. You should use forward slashes for directory separators.
If you do want to use backslashes at the least you should not add them at the end of variable assignments.
I'm trying to add function iceemdan() to the open source library libeemd.c. I'm trying to debug it with an IDE. The make file's first call to clang result's in clang's inability to find the gsl library, even though it is present and the make file upon which the IDE's make file is based has no trouble linking to gsl.
Here's the make file output (gsl errors and context only) using the Codelite IDE make file:
Executing Pre Build commands ...
Done
make[1]: Leaving directory '/Users/Common/iceemdan-dev/iceemdan-dev/iceemdan-clang'
make[1]: Entering directory '/Users/Common/iceemdan-dev/iceemdan-dev/iceemdan-clang'
clang -o ./Debug/iceemdan-clang #"iceemdan-clang.txt" -L.
Undefined symbols for architecture x86_64:
"_gsl_linalg_solve_tridiag", referenced from:
_emd_evaluate_spline in main.c.o
"_gsl_poly_dd_eval", referenced from:
_emd_evaluate_spline in main.c.o
"_gsl_poly_dd_init", referenced from:
_emd_evaluate_spline in main.c.o
"_gsl_ran_gaussian", referenced from:
_iceemdan in main.c.o
_eemd in main.c.o
_ceemdan in main.c.o
"_gsl_rng_alloc", referenced from:
_allocate_eemd_workspace in main.c.o
"_gsl_rng_free", referenced from:
_free_eemd_workspace in main.c.o
"_gsl_rng_mt19937", referenced from:
_allocate_eemd_workspace in main.c.o
"_gsl_rng_set", referenced from:
_set_rng_seed in main.c.o
"_gsl_set_error_handler_off", referenced from:
_iceemdan in main.c.o
_eemd in main.c.o
_ceemdan in main.c.o
_emd_evaluate_spline in main.c.o
"_gsl_sf_sin", referenced from:
_main in main.c.o
"_gsl_stats_sd", referenced from:
_iceemdan in main.c.o
_eemd in main.c.o
_ceemdan in main.c.o
"_gsl_strerror", referenced from:
_emd_evaluate_spline in main.c.o
"_gsl_vector_view_array", referenced from:
_emd_evaluate_spline in main.c.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[1]: *** [iceemdan-clang.mk:82: Debug/iceemdan-clang] Error 1
make[1]: Leaving directory '/Users/Common/iceemdan-dev/iceemdan-dev/iceemdan-clang'
make: *** [Makefile:5: All] Error 2
This make file, a modification of the package make file to run on the Mac, works:
.PHONY: all clean install uninstall
version := 1.4.1
gsl_flags := $(shell pkg-config --libs --cflags gsl)
ifeq ($(gsl_flags),)
$(error Failed to query GSL complilation flags from pkg-config)
endif
gsl_flags += -DHAVE_INLINE
commonflags := -Wall -Wextra -std=c99 -pedantic -Wno-unknown-pragmas -Wshadow -Wpointer-arith
commonflags += $(CFLAGS)
commonflags += -g -DEEMD_DEBUG=0
#commonflags += -fopenmp
commonflags += -DCLANG
PREFIX ?= /usr
SONAME = -soname
ifeq ($(shell uname -s),Darwin)
SONAME = -install_name
endif
define uninstall_msg
If you used $(PREFIX) as the prefix when running `make install`,
you can undo the install by removing these files:
$(PREFIX)/include/eemd.h
$(PREFIX)/lib/libeemd.a
$(PREFIX)/lib/libeemd.so
$(PREFIX)/lib/libeemd.so.$(version)
endef
export uninstall_msg
all: libeemd.so.$(version) libeemd.a eemd.h
clean:
rm -f libeemd.so libeemd.so.$(version) libeemd.a eemd.h obj/eemd.o
rm -rf obj
install:
install -d $(PREFIX)/include
install -d $(PREFIX)/lib
install -m644 eemd.h $(PREFIX)/include
install -m644 libeemd.a $(PREFIX)/lib
install libeemd.so.$(version) $(PREFIX)/lib
cp -Pf libeemd.so $(PREFIX)/lib
uninstall:
#echo "$$uninstall_msg"
obj:
mkdir -p obj
obj/eemd.o: src/eemd.c src/eemd.h | obj
clang $(commonflags) -c $< $(gsl_flags) -o $#
libeemd.a: obj/eemd.o
$(AR) rcs $# $^
libeemd.so.$(version): src/eemd.c src/eemd.h
clang $(commonflags) $< -fPIC -shared -Wl,$(SONAME),$# $(gsl_flags) -o $#
ln -sf $# libeemd.so
eemd.h: src/eemd.h
cp $< $#
The Codelite second level make file is here. (The first level merely calls it.) I'm running in a different directory to avoid overwriting my good code.
##
## Auto Generated makefile by CodeLite IDE
## any manual changes will be erased
##
## Debug
ProjectName :=iceemdan-clang
ConfigurationName :=Debug
WorkspacePath :=/Users/Common/iceemdan-dev/iceemdan-dev
ProjectPath :=/Users/Common/iceemdan-dev/iceemdan-dev/iceemdan-clang
IntermediateDirectory :=./Debug
OutDir := $(IntermediateDirectory)
CurrentFileName :=
CurrentFilePath :=
CurrentFileFullPath :=
User :=Coleman Family
Date :=08/08/2018
CodeLitePath :="/Users/Common/Library/Application Support/CodeLite"
LinkerName :=clang
SharedObjectLinkerName :=clang -shared -fPIC
ObjectSuffix :=.o
DependSuffix :=
PreprocessSuffix :=.o.i
DebugSwitch :=-gstab
IncludeSwitch :=-I
LibrarySwitch :=-l
OutputSwitch :=-o
LibraryPathSwitch :=-L
PreprocessorSwitch :=-D
SourceSwitch :=-c
OutputFile :=$(IntermediateDirectory)/$(ProjectName)
Preprocessors :=
ObjectSwitch :=-o
ArchiveOutputSwitch :=
PreprocessOnlySwitch :=-E
ObjectsFileList :="iceemdan-clang.txt"
PCHCompileFlags :=
MakeDirCommand :=mkdir -p
LinkOptions :=
IncludePath := $(IncludeSwitch). $(IncludeSwitch).
IncludePCH :=
RcIncludePath :=
Libs :=
ArLibs :=
LibPath := $(LibraryPathSwitch).
##
## Common variables
## AR, CXX, CC, AS, CXXFLAGS and CFLAGS can be overriden using an environment variables
##
AR := ar rcus
CXX := clang++
CC := clang
CXXFLAGS := -g -O0 -Wall $(Preprocessors)
CFLAGS := $(commonflags) $< -fPIC -shared -Wl $# $(gsl_flags) -o $# $(Preprocessors)
ASFLAGS :=
AS := llvm-as
##
## User defined environment variables
##
CodeLiteDir:=/Applications/codelite.app/Contents/SharedSupport/
PATH:=/Users/Common/usr/local/bin:/Library/Frameworks/Python.framework/Versions/2.7/bin:/Library/Frameworks/Python.framework/Versions/3.5/bin:/opt/local/bin:/opt/local/sbin:/Library/Frameworks/Python.framework/Versions/2.7/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Library/TeX/texbin:/opt/local/include
Srcs=main.c
Objects0=$(IntermediateDirectory)/main.c$(ObjectSuffix)
Objects=$(Objects0)
##
## Main Build Targets
##
.PHONY: all clean PreBuild PrePreBuild PostBuild MakeIntermediateDirs
all: $(OutputFile)
$(OutputFile): $(IntermediateDirectory)/.d $(Objects)
#$(MakeDirCommand) $(#D)
#echo "" > $(IntermediateDirectory)/.d
#echo $(Objects0) > $(ObjectsFileList)
$(LinkerName) $(OutputSwitch)$(OutputFile) #$(ObjectsFileList) $(LibPath) $(Libs) $(LinkOptions)
MakeIntermediateDirs:
#test -d ./Debug || $(MakeDirCommand) ./Debug
$(IntermediateDirectory)/.d:
#test -d ./Debug || $(MakeDirCommand) ./Debug
PreBuild:
#echo Executing Pre Build commands ...
$(eval gsl_flags = -L/opt/local/lib -lgsl -lgslcblas -lm -I/opt/local/include -DHAVE_INLINE)
$(eval commonflags := -Wall -Wextra -std=c99 -pedantic -Wno-unknown-pragmas -Wshadow -Wpointer-arith)
$(eval commonflags += $(CFLAGS))
$(eval commonflags += -g -DEEMD_DEBUG=0)
$(eval commonflags += -DCLANG)
$(eval PREFIX ?= /usr)
#echo Done
# all
Debug/main.c.o: main.c
#src/eemd.h | Debug
clang $(commonflags) -c $< $(gsl_flags) -o $#
Debug/main.c.a: Debug/main.c.o
$(AR) rcs $# $^
eemd: main.c src/eemd.h
clang $(commonflags) $< -fPIC -shared -Wl, ,$# $(gsl_flags) -o $#
My apologies for the length of this post. In the past, I've only run unmodified make files, not debug them. So, a lot of this is new and not transparent to me. I'd appreciate any help.
I had to trick the command for building main.c.o using global variables.
With this simplified example Makefile
PHONY: all
all: prog_main
prog_main.c:
echo 'int module(); int main(){return module();}' > $#
module.c:
echo 'int module(){return 0;}' > $#
main_objects := module.o
prog_%: prog_%.o $(%_objects)
$(CC) -o $# $< $($*_objects)
a make will fail, because
the syntax $(%_objects) is not supported by make and ignored,
module.o is not a dependency of prog_main,
make sees no need to compile module.o, and
the link fails, because there is no module.o.
Is there a way to tell make, that each prog_% depends on prog_%.o and the targets listed int the variable %_objects?
You can't do what your describing as make expands % and variables at different times during processing. But you could replace the line: main_objects := module.o with prog_main: modules.o. If you did that, then module.o would appear in $^ in the prog_%: recipes. So you would have something like:
.PHONY: all
all: prog_main
prog_main.c:
echo 'int module(); int main(){return module();}' > $#
module.c:
echo 'int module(){return 0;}' > $#
# main_objects := module.o
prog_main: module.o
prog_%: prog_%.o
$(CC) -o $# $^
this is my makefile :
#Makefile
CC=g++
CFLAGS=-lcppunit
OBJS=Money.o MoneyTest.o
all : $(OBJS)
$(CC) $(OBJS) -o TestUnitaire
#création des objets
Money.o: Money.cpp Money.hpp
$(CC) -c Money.cpp $(CFLAGS)
MoneyTest.o: MoneyTest.cpp Money.hpp MoneyTest.hpp
$(CC) -c MoneyTest.cpp $(CFLAGS)
clean:
rm *.o $(EXEC)
when i run this makefile, i get errors like those :
g++ Money.o MoneyTest.o -o TestUnitaire
Money.o: In function main':
Money.cpp:(.text+0x3c): undefined reference toCppUnit::TestFactoryRegistry::getRegistry(std::basic_string, std::allocator > const&)'
Money.cpp:(.text+0x78): undefined reference to CppUnit::TextTestRunner::TextTestRunner(CppUnit::Outputter*)'
Money.cpp:(.text+0x8c): undefined reference toCppUnit::TestRunner::addTest(CppUnit::Test*)'
Money.cpp:(.text+0x98): undefined reference to CppUnit::TextTestRunner::result() const'
Money.cpp:(.text+0xec): undefined reference toCppUnit::CompilerOutputter::CompilerOutputter(CppUnit::TestResultCollector*, std::basic_ostream >&, std::basic_string, std::allocator > const&)'
Money.cpp:(.text+0xfc): undefined reference to CppUnit::TextTestRunner::setOutputter(CppUnit::Outputter*)'
Money.cpp:(.text+0x168): undefined reference toCppUnit::TextTestRunner::run(std::basic_string, std::allocator >, bool, bool, bool)'
Money.cpp:(.text+0x1a5): undefined reference to CppUnit::TextTestRunner::~TextTestRunner()'
Money.cpp:(.text+0x233): undefined reference toCppUnit::TextTestRunner::~TextTestRunner()'
It's seems to be that there no link between my class. What's the trouble ?
The -lcppunit flag is not correct in CFLAGS, which is where you put C compiler flags. You are (a) compiling C++ programs, not C programs, and (b) the -l flag is a linker flag, not a compiler flag. Also, the CC variable holds the C compiler. You should use the CXX variable for the C++ compiler. Your makefile should look something like:
#Makefile
CXX = g++
LDLIBS = -lcppunit
OBJS = Money.o MoneyTest.o
all : TestUnitaire
TestUnitaire: $(OBJS)
$(CXX) $^ -o $# $(LDFLAGS) $(LDLIBS)
#création des objets
%.o : %.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $# -c $<
Money.o: Money.hpp
MoneyTest.o: Money.hpp MoneyTest.hpp
clean:
rm *.o $(EXEC)
In continuation with my earlier question
Makefile - compiling back and forth
I made an attempt in creating a single Makefile. The two subdirectories are HAM-src and GFS-src. However, I am still unable to build it. I paste my Makefile below:
export
SHELL = /bin/sh
top_srcdir=./Temp
objdir=$(top_srcdir)/obj
bindir=${exec_prefix}/bin
cfssrcdir=${top_srcdir}/GFS-src
hamsrcdir=${top_srcdir}/HAM-src
incdir=${top_srcdir}/include
exec=${bindir}/esm_gfs-ham_v0
PROG=$(exec)
LDR = mpxlf90_r -qsmp=noauto
FFLAG90 = $(OPTS90) $(FINCS) -qfree=f90 -NS2048 -qmoddir=$(objdir) -I$(objdir)
FFLAGM = -NS2048 -qfixed -qmoddir=$(objdir) -I$(objdir)
F77 = mpxlf95
F90 = mpxlf95
F90_x = xlf90_r
F90_r = mpxlf95_r
SRCHAM = $(hamsrcdir)/ham_control.f90 $(hamsrcdir)/mo_filename.f90 \
$(hamsrcdir)/ham_namelist.f90 $(hamsrcdir)/ham_submodel.f90 \
$(hamsrcdir)/ham_submodel_diag.f90 $(hamsrcdir)/ham_ham.f90
SRCGFS_MOD=$(cfssrcdir)/machine.f $(cfssrcdir)/resol_def.f \
$(cfssrcdir)/omegas.f $(cfssrcdir)/cnvcld_v.f
OBJGFS_MOD = $(patsubst $(cfssrcdir)/%.f,$(objdir)/%.o,$(SRCGFS_MOD))
OBJHAM = $(patsubst $(hamsrcdir)/%.f90,$(objdir)/%.o,$(SRCHAM))
.SUFFIXES: $(SUFFIXES) .f90 .f .o
all: $(PROG)
$(PROG): $(OBJHAM) $(OBJGFS_MOD)
$(LDR) $(CFS_LDFLAGS) -o $# $(OBJGFS_MOD) $(OBJHAM) $(CFS_LIBS) -L$(LDFLAGS)
$(objdir)/%.o: $(cfssrcdir)/%.f
$(F77) $(FFLAGS) -c $< -o $#
$(objdir)/%.o: $(hamsrcdir)/%.f90
$(F90_r) $(F90FLAGS) -c $< -o $#
########## dependencies for $(hamsrcdir) ###########
ham_filename.o: ham_control.o
ham_namelist.o: ham_control.o ham_filename.o
ham_submodel.o: ham_control.o ham_namelist.o $(objdir)/resol_def.o
ham_submodel_diag.o: ham_submodel.o
########## dependencies for $(cfssrcdir) ###########
$(objdir)/omegas.o: $(cfssrcdir)/omegas.f
$(F77) $(FFLAGM) -c $(cfssrcdir)/omegas.f -o $#
$(objdir)/cnvcld_v.o: $(cfssrcdir)/cnvcld_v.f
$(F77) $(FFLAGM) -c $(cfssrcdir)/cnvcld_v.f -o $#
The error:
mpxlf95_r -q64 -O3 -qstrict -qMAXMEM=-1 -qarch=auto -qtune=auto -qcache=auto -qfloat=fltint -qsuffix=cpp=f90 -lessl_r -lmass -lmassv -I./Temp/include -I./Temp/HAM-src -qmoddir=./Temp/obj -I./Temp/obj -c ./Temp/HAM-src/ham_namelist.f90 -o ./Temp/obj/ham_namelist.o
** ham_namelist === End of Compilation 1 ===
1501-510 Compilation successful for file ham_namelist.f90.
mpxlf95_r -q64 -O3 -qstrict -qMAXMEM=-1 -qarch=auto -qtune=auto -qcache=auto -qfloat=fltint -qsuffix=cpp=f90 -lessl_r -lmass -lmassv -I./Temp/include -./Temp/HAM-src -qmoddir=./Temp/obj -I./Temp/obj -c ./Temp/HAM-src/ham_submodel.f90 -o ./Temp/obj/ham_submodel.o
"./Temp/HAM-src/ham_submodel.f90", line 425.7: 1514-219 (S) Unable to access module symbol file for module resol_def. Check path and file permissions of file. Use association not done for this module.
1501-511 Compilation failed for file ham_submodel.f90.
gmake: *** [/gpfs1/home/cccrmod/ham_expt_dec11/regrid_test/CFS-HAM/SORC_CFS-HAM/Temp/obj/ham_submodel.o] Error 1
Why makefile does not compile the resol_def.f module on encountering the dependency?
Another issue - my makefile is not working properly. It goes in a sequence in which the sources are defined.
This is difficult to untangle (a minimal, complete example really would help), but I'd suggest you change this
ham_submodel.o: ham_control.o ham_namelist.o $(objdir)/resol_def.o
to this
$(objdir)/ham_submodel.o: ham_control.o ham_namelist.o $(objdir)/resol_def.o
and see if that solves the first problem. I don't understand the last line of your question ("Another issue...").