How to build a project without make (bare shell script)? - shell

I heard that back in the old days (or maybe not so old), before the make utility was included in Unix, people used to write shell script to "make" and "install" their software.
Consider a project with: 2 source files main.c and util.c, a header util.h that uses the OpenGL library and needs to run on Ubuntu.
(Ubuntu and OpenGL are used just for the sake of being specific)
What would such a script actually need to do? Where can I find an example?

It's hard to imagine why anyone would want to revisit "the bad old days" before make, but it's actually not too difficult for a simple project. So given your particular example, a shell script to compile might look like this:
gcc -Wall -c main.c -o main.o -lglut -lglm
gcc -Wall -c util.c -o util.o -lglut -lglm
gcc -Wall main.o util.o -o main -lglut -lglm
What it does is to simply run through the entire "recipe" to build the project every time. The advantage is that, if the source code is all correct, it should result in an executable. The considerable disadvantages are that
if any step fails, so will subsequent steps that rely on the failed step
everything is rebuilt every time, wasting a lot of time
compile and link flags are all embedded into the script and hard to change
this approach has little hope of cross-platform compatibility
One can tinker with the basic shell script to improve on various aspects of this. Then, when that proves inadequate, one could write a program to do these things better. At that point, in essence, you will have re-invented make.

Related

Automating GCC Compiler arguments to create easier compilations - Windows OS?

Goal
When I run the command:
gcc -ggdb -std=c99 -Wall -Werror hello.c -lcs50 -o test.exe from the root directory
I am able to build the test.exe file and when I run test.exe all is well (thanks to this post by Manohar Reddy Poreddy)
However all of those flags are a little bit cumbersome and I think it would great to condense them into a 'make' command or similar. How would I do this on windows?
Context
GCC, G++ and GDB all seem to be correctly linked (I used chocolatey which paths everything automatically)
Okay so I found what I was looking for.
I hope this answer can help others. Turns out the utility is called 'make' (no surprises). In your directory you essentially create a 'makefile' where you can include your command line arguments which saves on repeated typing in the command line for each compile.
Here is an excellent response on how to install 'make' for windows and was perfect for my use case as a Chocolatey user.
I also found this resource which helps newcomers begin to get their head round GCC which I highly recommend if you're coming into this like I was and felt completely out of your depth.

Can a CMD batch file or PowerShell script execute multiple g++ commands?

I like using both Linux and Windows for my C and C++ coding and I prefer using the command line to compile my programs. I can run make on Linux, which is fine. But on Windows, now that I'm working with classes and have to compile multiple files, I find it a chore to type in several g++ commands to compile the class and main object files.
I was wondering if there's a way to get a CMD batch file or PowerShell script to just execute the commands one after the other?
Something like this:
g++ -c Area.cpp -o Area.o
g++ -c Convert.cpp -o Convert.o
g++ -c Calculate.cpp -o Calculate.o
g++ -c multi_menu_functions.cpp -o multi_menu_functions.o
g++ -c main.cpp -o main.o
g++ -Wall main.o Area.o Calculate.o Convert.o multi_menu_functions.o -o main
...Something dead simple and easy.
Just write the commands in a file with extension .bat and you can just start that file. You can turn off outputting the commands while execution of the batch file by starting the file with the line #echo off.
Or better yet: Just get make for windows and use that one.
I figured out the issue of why the g++ commands wouldn't work as is: somehow the laptop I was using didn't grant me the correct permissions. At a guess I tried the full path name for g++.exe and it worked. I reconfigured some things and now it works with the commands as listed.
On a side note; I did get gnumake and minGW make working as well. Since these can run my Linux makefiles I'll use these as well.

How can I specify include and library locations for mingw32-make under msys2?

I have a suite of Windows programs that up to now I have built under msys, one of which uses libxml2. I am currently trying to switch to building them under msys2 and the latter one is hitting a problem. My updated Makefile includes this:
CFLAGS += -I/mingw32/include/libxml2
$(BINDIR)/%.o: %.c
#-$(MKDIR) $(BINDIR)
$(CC) $(CFLAGS) -c $*.c -o $#
But when I run make (mingw32-make) the compile fails as follows:
[csv-gen]: mingw32-make
gcc -std=c99 -Werror -Wall -D_XOPEN_SOURCE -O -I/mingw32/include/libxml2 -c xmlParse.c -o ../../bin/Win32/csv-gen/xmlParse.o
xmlParse.c:36:27: fatal error: libxml/parser.h: No such file or directory
#include "libxml/parser.h"
^
compilation terminated.
Makefile:66: recipe for target '../../bin/Win32/csv-gen/xmlParse.o' failed
mingw32-make: *** [../../bin/Win32/csv-gen/xmlParse.o] Error 1
Yet that libxml/parser.h file does exist under the /mingw32/include/libxml2 path given by the -I option:
[csv-gen]: ls /mingw32/include/libxml2/libxml/parser.h
/mingw32/include/libxml2/libxml/parser.h
And the strange thing is that if I run the exact same gcc command directly from the msys bash shell (copying and pasting it from the make output above) then it compiles fine with no errors.
And I have the exact same problem with the link phase where it doesn't find the libxml2.a library in the path given to gcc by -L/mingw32/lib, and again I run the gcc link command directly from the shell and it works fine.
So why would gcc's -I/mingw32/include/libxml2 and -L/mingw32/lib options not work when run via mingw32-make yet the exact same options work fine on calling gcc directly from the shell?
I did try making the paths explicit Windows paths (d:/msys64/mingw32/...) and also tried quoting them, to no avail.
It turned out that the answer was to use explicit Windows paths, which as I said above I had tried, but when I tried again it worked so I must have previously made some mistake doing that. I found this by using the output from pkg-config which gives:
[csv-gen]: pkg-config --cflags libxml-2.0
-ID:/msys64/mingw32/include/libxml2
So apparently the problem is that mingw32-make doesn't fully understand the msys filing system, or at least not /mingw32 and /mingw64 paths in it.

Conditional linking in Makefile

In my Makefile, I want to link to a library only if it is installed on the machine. So, for example if the library is hwloc, I want to do the following:
xfoo : foo.o
if (hwloc installed)
gcc foo.o -o $# -lhwloc
else
gcc foo.o -o $#
Is there anyway to do something like this? i.e. Is it possible to check if a specific library is installed and use that as a condition in a Makefile?
Here's the wrong answer:
xfoo : foo.o
if (hwloc installed); then gcc foo.o -o $# -lhwloc; else gcc foo.o -o $#; fi
Commands executed from a Makefile do not have to be just simple, single commands. Anything that a shell can execute, can be invoked from a Makefile. Including an entire script, sandwiched into one line.
Here's the right answer:
However, the above approach is the wrong one. You will find that many free software packages do this kind of thing all the time: conditionally link in a library, if it's available.
But the way that it's done is by running a separate configure script, before running make. Go grab the source tarball to a random free software package, of your choosing, and read the installation instructions. They will all tell you to run the configure script first, before running make.
A crushing majority of free software packages use the GNU toolchain to create their build system -- the configure script, and the Makefile. The GNU toolchain consists of autoconf and automake tools (also libtool in many cases). Go Google these, for more information.
There are also a few other, less popular toolchains, but the GNU toolchain is the most frequently one used, for this sort of a thing. So, to do something along the lines of what you're trying to do, the way this gets typically done is:
In the configure.ac file:
AC_CHECK_LIB(hwloc,some_function_in_the_hwloc_library,[LINK_HWLOC=-lhwloc])
AC_SUBST(LINK_HWLOC)
In the Makefile.am file:
hwloc_LDADD=#LINK_HWLOC#
That's it. That's the way this is done the countless number of times most free software packages need to do this exact same thing. autoconf and automake will take care of writing the shell script and the makefile, that implements this.
I don't have access to a Linux machine at the moment so pardon me my answer will be untested.
I will respectfully disagree with both of my predecessors.
First, using autotools to amend an existing Makefile is a bad idea. Autotools are made to avoid worrying about creating a good Makefile in a simple use case. It's as if OP asked "How to change + to - in my Python script" and the answer was "write a shell script to modify the script, save it in temporary file and execute the file"
Second answer, why do something manually when it can be painlessly done automatically?
So, IMHO the correct answer is, this is the exact use case for $(wildcard):
xfoo: foo.o $(wildcard libhwloc.a)
gcc $(patsubst lib%.a, -l%, $^) -o $#
Note: the library is installed or not ahead of time but not to be made during the build.
If you don't want to get involved with the autotools/etc. for this (which while a reasonable solution is also reasonable to want to avoid for something this simple) and you don't want to have to play guessing games about where people may or may not have this hwloc library installed then the best you can do is to let people turn the feature on manually.
Use three (or four) make variables. USE_HWLOC, HWLOC_LDLIBS, HWLOC_CFLAGS and possibly HWLOC_LDFLAGS.
Then when USE_HWLOC is defined you link against the library and use the other three variables in case they have also been set.
ifdef USE_HWLOC
HWLOC:=-lhwloc
else
HWLOC:=
HWLOC_LDLIBS:=
HWLOC_LDFLAGS:=
HWLOC_CFLAGS:=
endif
xfoo : foo.o
gcc foo.o -o $# $(HWLOC_LDLIBS) $(HWLOC)

Set gcc and g++ optimization flags permanently

I'm running a x86 kernel on an x64 machine. I would like to compile libraries for a i586 processor. During compilation, some libraries use i686 optimization, so want to set -mtunes=i586, -march=i586 and -O3 flags for all of libraries even if they explicitly declare something else in their makefiles.
Somehow I want to set compiler flags permanently...
Regardless of whether you should do this, here's the easiest way to do it:
Create a new file with the following contents:
#!/bin/sh
exec /usr/bin/gcc "$#" -O3 -mtunes=i586 -march=i586
Change /usr/bin/gcc to your actual compiler if that's not right on your system.
Save it as ~/bin/gcc.
Make the new script executable:
chmod +x ~/bin/gcc
Repeat to create another file for g++.
Add ~/bin to the start of your path:
export PATH=~/bin:$PATH
Compile your project. Whenever your new scripts are on the path they will override whatever the makefile says.
Hope that helps.
P.S. The best way to do it (rather than the easiest) would probably be to mess with the compiler's "specs" file, but it's much harder to explain and do.

Resources