I know how to write Makefiles for Linux, and was hoping it would be similar in Windows. However, from what I've seen on the internet, it is quite difficult.
If I have one file main.cpp, what would be the simplest form of a Makefile? Also, what would be the command to make Makefile ?
Thanks!
In brief...
$ ls && cat main.cpp && cat Makefile && make && ./main
Makefile main.cpp
/* main.cpp */
#include <iostream>
int main(int, char **) {
std::cout << __func__ << "#" << __FILE__ << ":" << __LINE__ << std::endl;
return EXIT_SUCCESS;
}
# Makefile
all: main
clean: ; rm -f main
g++ main.cpp -o main
main#main.cpp:4
$
That's as bare-bones as I can make it.
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.
Similar questions got asked a lot, but I still don't quite get what's wrong with how I compiled and installed my shared library.
As far as compiling goes I do
> gcc -c -fPIC libt.c
> gcc -shared -Wl,-soname,libt.so.0 -o libt.so.0.1 libt.o
In order to install the library I run
> cp libt.so.0.1 /usr/local/lib/
> cp libt.h /usr/local/include/
> ln -s /usr/local/lib/libt.so.0.1 /usr/local/lib/libt.so.0 # ldconfig would setup this symlink itself ...
> ln -s /usr/local/lib/libt.so.0 /usr/local/lib/libt.so # ... but not this one, so I do it myself
> sudo ldconfig
/usr/local/lib is included in /etc/ld.so.conf.d/libc.conf, and ldconfig -p | grep libt yields
libt.so.0 (libc6,x86-64) => /usr/local/lib/libt.so.0
libt.so (libc6,x86-64) => /usr/local/lib/libt.so
So, as far as I can tell, everything looks okay until this point. However, compiling a program that's supposed to use my library fails:
> gcc -o prog main.c -llibt
/usr/bin/ld: cannot find -llibt
libt.h
#ifndef libt_h__
#define libt_h__
extern int add(int, int);
#endif
libt.c
int
add(int a, int b)
{
return a + b;
}
main.c
#include <stdio.h>
#include <stdlib.h>
#include "libt.h"
void
print_usage()
{
printf("usage: ./prog <number a> <number b>\n");
}
int
main(int argc, char *argv[])
{
int a = 0, b = 0, c = 0;
if (argc != 3) {
print_usage();
return 1;
}
a = atoi(argv[1]);
b = atoi(argv[2]);
c = add(a, b);
printf("%d\n", c);
return 0;
}
Figured it out. While library names have to be prefixed with "lib", that prefix must not be specified when linking. That is, gcc -o prog main.c -llibt is wrong while gcc -o prog main.c -lt works as expected.
I am trying to make my first C++ app with embedded Dart VM. I have a problem with minimal setup of compiler on my MacOS 10.14.6. My build is successful, but when I start the app, it crashed with:
$ clang++ -I ${HOME}/opt/dart-sdk --define-macro DART_SHARED_LIB=1 -L ./libs/debug -ldart_jit -lm -lz -O2 -undefined dynamic_lookup -o reproduce *.cpp
$ ./reproduce
dyld: Symbol not found: __ZN4dart13FLAG_profilerE
Although symbol __ZN4dart13FLAG_profilerE presents inside binary
$ nm reproduce | grep __ZN4dart13FLAG_profilerE
U __ZN4dart13FLAG_profilerE
How to compile/link this properly?
My reproduce program is:
#include <iostream>
#include <include/dart_api.h>
int main(int argc, const char * argv[]) {
char* setVMFlagsError = Dart_SetVMFlags(argc, argv);
if (setVMFlagsError != nullptr) {
std::cerr << "Error while set Dart VM flags: " << setVMFlagsError << "\n";
::free(setVMFlagsError);
return 1;
} else {
Dart_InitializeParams params = {};
std::cout << "Hello, World!\n";
return 0;
}
}
Dart SDK was built following by official documentation
(dart-sdk-pyenv) ~/tmp/dart-sdk/sdk $ ./tools/build.py --mode all --arch x64 create_sdk
(dart-sdk-pyenv) ~/tmp/dart-sdk/sdk $ cp -a ~/tmp/dart-sdk/sdk/xcodebuild/DebugX64/dart-sdk ~/opt/
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I'm practically done with my project, all I need now is to write a bash script that should compile and execute the program. My instructions are that we should provide a script that should compile the program and the instructor should be able to run the program by typing in Project1 Value1 Value2. I'm kinda lost on this one, so any help would be appreciated.
I have tried to compile the program by running this script
#!/bin/bash
echo $1
echo $2
g++ -std=c++11 Project2.cpp -lpthread -o project1
./project1 $1 $2
Edit
#!/bin/bash
g++ -std=c++11 Project2.cpp -lpthread -o project1
I thought about it a bit more, and I think my second version is closer to what I would like my script to do. Except I was hoping to be able to execute the program without using ./ if possible.
You have struggled for a few hours and put something together, but what happens if the compilation fails? What happens if there are no arguments? What happens if there are 4 arguments for the program?
When writing a script, or a program, the most important thing you can do is validate every necessary step! If you are expecting input, validate you received it. Once you have the input, validate it is what your expected. Is it a value within the usable range? Is it a filename that meets my requirements? Does it exist? Did my compile succeed or fail? Do I try and execute the program?
All of these need to be addressed. Otherwise, your script (or program) will stray off on some undefined path.
Bash provides a wealth of conditional expressions that can be used with test (or [...]) or using the bash [[...]] operator. See Bash Manual - 6.4 Bash Conditional Expressions. Make use of the language features to make your code robust.
Bash provides a wealth of string handling features through parameter expansions Bash Manual - 3.5.3 Shell Parameter Expansion, use them to check the extension to make sure it is c, cpp or c++
Putting those features together with a few if...then...fi statements will make your script much more reliable -- and actually do what it is you are trying to do.
The following short script takes arguments (bash Positional Parameters) requiring that at least the filename to compile be provided, and passing any additional arguments to the compiled program as command line arguments with ${#:2} (all bash positional parameters beginning with the 2nd one)
#!/bin/bash
if [ -z "$1" ] ## validate at least one argument given
then
printf "error: insufficient arguments\n" >&2
printf "usage: %s file.cpp [args]\n" "${0##*/}" >&2
exit 1
fi
if [ ! -r "$1" ] ## validate file is readable
then
printf "error: file not found '%s'\n" "$1" >&2
exit 1
fi
src="$1" ## give source file a handy name
## check the source file ends in '.c', '.cpp' or '.c++'
if [ "${src##*.}" != 'c' -a "${src##*.}" != 'cpp' -a "${src##*.}" != 'c++' ]
then
printf "error: first argument not a c/c++ file\n" >&2
exit 1
fi
ext="${src##*.}" ## save the extension
if [ "${#ext}" = 'c' ] ## check if ext is 'c' use gcc else use g++
then
## always enable compiler warnings, -Wall -Wextra -pedantic, minimum
# -Wshadow to catch shadowed variables, -Werror treat warnings as error
gcc -Wall -Wextra -pedantic -Wshadow -Werror \
-std=c11 -O3 -o "${src%.*}" "$src"
else
g++ -Wall -Wextra -pedantic -Wshadow -Werror \
-std=c++11 -O3 -o "${src%.*}" "$src"
fi
if [ $? -eq '0' ] ## check the compiler return, run only on success
then
./"${src%.*}" ${#:2}
else
printf "\nAn error occurred, executable not called\n\n" >&2
fi
Now a couple of short examples to make sure it works:
#include <stdio.h>
int main (int argc, char **argv) {
const char *s = "hello c file.";
printf ("%s\n", s);
for (int i = 1; i < argc; i++)
printf ("arg[%d]: %s\n", i, argv[i]);
}
Example Use/Output
$ bash compilewargs.sh cfile.c foo bar baz
hello c file.
arg[1]: foo
arg[2]: bar
arg[3]: baz
For C++
#include <iostream>
#include <string>
int main (int argc, char **argv) {
std::string s = "hello cpp file.";
std::cout << s << '\n';
for (int i = 1; i < argc; i++)
std::cout << "arg[" << i << "]: " << argv[i] << '\n';
}
Example Use/Output
$ bash compilewargs.sh cppfile.cpp foo bar baz
hello cpp file.
arg[1]: foo
arg[2]: bar
arg[3]: baz
Does the error-handling work?
#include <stdio.h>
int main (void) {
const char *s = "hello c file.";
printf ("%s\n", unknown);
}
Example Use/Output
$ bash compilewargs.sh cerrfile.c foo bar baz
cerrfile.c: In function ‘int main()’:
cerrfile.c:7:21: error: ‘unknown’ was not declared in this scope
printf ("%s\n", unknown);
^
cerrfile.c:5:17: error: unused variable ‘s’ [-Werror=unused-variable]
const char *s = "hello c file.";
^
cc1plus: all warnings being treated as errors
An error occurred, executable not called
What about a file that doesn't exist?
$ bash compilewargs.sh myfile.c foo bar baz
error: file not found 'myfile.c'
What about a text (or any other non-c, cpp or c++) file?
$ bash compilewargs.sh compilewargs.sh foo bar baz
error: first argument not a c/c++ file
By taking the time to think though what the dumbest user you know could ever try and do with your script -- and protecting against it, you can write reasonably robust scripts that will save you grief. Look things over and let me know if you have further questions.
I ended up figuring it out after a while.
#!/bin/bash
echo "Enter TP"
read TP
echo "Enter TC"
read TC
g++ -std=c++11 Project_1.cpp -lpthread -o Project_1
./Project_1 $TP $TC
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...