Makefile Combining Object Creation With Linking - windows

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.

Related

Make is not recognizing my library!

I am trying to create a program in C++ that utilizes the rudeconfig library.
I run make, and get this:
g++ -o Homework5_executable helloworld.o -lrudeconfig -L/home/j/je/jea160530/hw5/libs
/bin/ld: cannot find -lrudeconfig
collect2: error: ld returned 1 exit status
make: *** [Homework5_executable] Error 1
I know this is happening because make is not recognizing the rudeconfig library, however I have followed the instructions on the rudeconfig site for install correctly.
Here is the code:
Makefile
#
# Set up info for C++ implicit rule
CXX = g++
CXXFLAGS = -Wall
CPPFLAGS = -I/home/012/j/je/jea160530/hw5/include
#
# Set up any Linker Flags
LDFLAGS = -L/home/012/j/je/jea160530/hw5/libs
#
# Set up libraries needer for compilation
LDLIBS = -lrudeconfig
#
# We choose the project name. This is used in building the file name for the backup target
PROJECTNAME = JesseAlotto_Homework5
#
# We choose the source files to include and name the output
SRCS = helloworld.cc
#
# We choose the name of the executable to be created
EXEC = Homework5_executable
#
# NORMALLY DON'T NEED TO CHANGE ANYTHING BELOW HERE
# =================================================
#
OBJS = $(SRCS:cc=o)
all: $(EXEC)
clean:
rm -f $(OBJS) *.d *~ \#* $(EXEC)
Makefile: $(SRCS:.cc=.d)
# Pattern for .d files.
# =====================
%.d:%.cc
#echo Updating .d Dependency File
#set -e; rm -f $#; \
$(CXX) -MM $(CPPFLAGS) $< > $#.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $# : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$
# This is a rule to link the files. Pretty standard
# ================================================
$(EXEC): $(OBJS)
$(CXX) -o $(EXEC) $(OBJS) $(LDFLAGS) $(LDLIBS)
#echo Program compiled succesfully!
#
# Backup Target
# =============
backup: clean
#mkdir -p ~/backups; chmod 700 ~/backups
#$(eval CURDIRNAME := $(bash pwd))
#$(eval MKBKUPNAME := ~/backups/$(PROJECTNAME)-$(shell date +'%Y.%m.%d-%H:%M:%S').tar.gz)
#echo
#echo Writing Backup file to: $(MKBKUPNAME)
#echo
#tar -zcvf $(MKBKUPNAME) ./$(CURDIRNAME)
#chmod 600 $(MKBKUPNAME)
#echo
#echo Done!
#
# Include the dependency files
# ============================
-include $(SRCS:.cc=.d)
helloworld.cc
#include <string>
#include <iostream>
#include <fstream>
#include <tclap/CmdLine.h>
#include <map>
#include <stdlib.h>
#include <rude/config.h>
using namespace rude;
int main(int argc, char *argv[]){
std::string nextLine;
std::map<int, std::string> optionMap;
try{
std::cout << "hello world!";
//Command Line Variable
TCLAP::CmdLine cmd("CS3377.002 Program 5", ' ', "1.0");
//Switch Args
TCLAP::SwitchArg daemonSwitch("d", "daemon", "Run in daemon mode (forks to run as a daemon).", cmd, false);
//Unlabeled Value Args
TCLAP::UnlabeledValueArg<std::string> infileArg("infile", "The name of the configuration file. Defaults to cs3376dirmond.conf", true, "cs3376dirmond.conf", "config filename", false);
//Add leftover flags to cmdLine object
cmd.add(infileArg);
//Parse the command line
cmd.parse(argc, argv);
//Create an enumeratedlist for the mapping
enum flags {DAEMON, INFILE};
//Map keys and values to map
if (daemonSwitch.getValue()){
optionMap[DAEMON] = "1";
}
else{
optionMap[DAEMON] = "0";
}
optionMap[INFILE] = infileArg.getValue();
//Load input file
std::ifstream inputFile;
inputFile.open(optionMap[INFILE].c_str(), std::ios::in);
if(!inputFile){
std::cerr << "Error: no input file" << std::endl;
}
//============================================PARSE CONFIGURATION FILE==========================
Config config;
config.load("cs3376dirmond.conf");
//==============================================================================================
inputFile.close();
return 0;
} catch (TCLAP::ArgException &e) //catch any exceptions
{ std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl;}
}
The error is caused by this command:
g++ -o Homework5_executable helloworld.o -lrudeconfig -L/home/j/je/jea160530/hw5/libs
not by make itself.
The error means that the linker isn’t finding librudeconfig.so in the library search path. From your comments, it turns out the library is named rudeconfig.so instead, so you need to specify
LDLIBS = -l:rudeconfig.so
instead of -lrudeconfig (which always expands to librudeconfig.so or librudeconfig.a).
Ideally, the library should be installed as librudeconfig.so...

undefined reference static library makefile

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

Why doesn't make build an object file on the first run?

I have this Makefile:
CFLAGS := $(CFLAGS) -std=c99
shell: main.o shellparser.o shellscanner.o
$(CC) -o shell main.o shellparser.o shellscanner.o
main.o: main.c shellparser.h shellscanner.h
shellparser.o: shellparser.h
shellparser.h: shellparser.y lemon
./lemon shellparser.y
shellscanner.o: shellscanner.h
shellscanner.h: shellscanner.l
flex --outfile=shellscanner.c --header-file=shellscanner.h shellscanner.l
# Prevent yacc from trying to build parsers.
# http://stackoverflow.com/a/5395195/79202
%.c: %.y
lemon: lemon.c
$(CC) -o lemon lemon.c
For some reason, on the first run of make, shellparser.o isn't built:
> make
cc -o lemon lemon.c
./lemon shellparser.y
flex --outfile=shellscanner.c --header-file=shellscanner.h shellscanner.l
cc -std=c99 -c -o main.o main.c
cc -std=c99 -c -o shellscanner.o shellscanner.c
cc -o shell main.o shellparser.o shellscanner.o
i686-apple-darwin10-gcc-4.2.1: shellparser.o: No such file or directory
make: *** [shell] Error 1
rm shellscanner.c
If I run it again, it then builds it correctly:
> make
cc -std=c99 -c -o shellparser.o shellparser.c
cc -o shell main.o shellparser.o shellscanner.o
So what do I have out-of-order such that it doesn't build it the first time?
The first time you try to build, Make doesn’t know that lemon outputs shellparser.c, so it doesn’t try to build it. When you rebuild, shellparser.c does exist, so Make uses it. The solution is to explicitly tell Make that lemon outputs shellparser.c:
diff --git a/Makefile b/Makefile
index bf2655e..d6b288d 100644
--- a/Makefile
+++ b/Makefile
## -7,7 +7,7 ## main.o: main.c shellparser.h shellscanner.h
shellparser.o: shellparser.h
-shellparser.h: shellparser.y lemon
+shellparser.c shellparser.h: shellparser.y lemon
./lemon shellparser.y
shellscanner.o: shellscanner.h
diff --git a/main.c b/main.c
index 81ec151..4179981 100644
--- a/main.c
+++ b/main.c
## -33,7 +33,7 ## void parse(const char *commandLine) {
}
// Borrowed from http://stackoverflow.com/a/314422/79202.
-char * getline(void) {
+char * my_getline(void) {
char * line = malloc(100), * linep = line;
size_t lenmax = 100, len = lenmax;
int c;
## -69,7 +69,7 ## int main(int argc, char** argv) {
void* shellParser = ParseAlloc(malloc);
char *line;
printf("> ");
- while ( line = getline() ) {
+ while ( line = my_getline() ) {
parse(line);
printf("> ");
}
Also I renamed getline so it would build on my mac; thanks for posting all your source!

makefile-compiling-back-and-forth - follow up

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...").

Variable substitution error

Does anyone know what is wrong with my Makefile?
CXX = g++ # compiler
CXXFLAGS = -g -Wall -MMD # compiler flags
MAKEFILE_NAME = ${firstword ${MAKEFILE_LIST}} # makefile name
OBJECTS1 = utf.o # object files forming executable
EXEC1 = utf # executable name
OBJECTS2 = driver.o rational.o # object files forming executable
EXEC2 = rational # executable name
OBJECTS3 = da.o qa.o pa.o ua.o # object files forming executable
EXEC3 = ho # executable name
OBJECTS = ${OBJECTS1} ${OBJECTS2} ${OBJECTS3}
EXECS = ${EXEC1} ${EXEC2} ${EXEC3}
DEPENDS = ${OBJECTS:.o=.d} # substitute ".o" with ".d"
.PHONY : all clean
all : ${EXECS}
${EXEC1} : ${OBJECTS1} # link step
${CXX} $^ -o $#
${EXEC2} : ${OBJECTS2} # link step
${CXX} $^ -o $#
${EXEC3} : ${OBJECTS3} # link step
${CXX} $^ -o $#
${OBJECTS} : ${MAKEFILE_NAME} # OPTIONAL : changes to this file => recompile
-include ${DEPENDS} # include *.d files containing program dependences
clean : # remove files that can be regenerated
rm -f ${DEPENDS} ${OBJECTS} ${EXECS}
Error:
./Makefile: 1: CXX: not found
./Makefile: 2: CXXFLAGS: not found
./Makefile: 3: Bad substitution
use the make command to run the Makefile. you can specify a target for make, like make all.
Don't execute the makefile on its own. Your shell is trying to treat it as a shell script of some kind.
Run make, which uses the makefile.

Resources