Bash script for creating new C project using gcc
or clang
compiler, make
a and Criterion (https://github.com/Snaipe/Criterion.git) testing library. Inspired by tremendous videos by Jacob Sorber, (https://www.youtube.com/jacobsorber).
When invoked from a directory outside your project, it will create one. When invoked inside a project root, it will add a source file to the project. The created file might be a *.h
file, then it just adds the #ifndef
guard into it that corresponds with file name. If the file added is a *.c
file, it will:
- Add the
*.c
file - Add an
#include
directive to include its prototypes from corresponding header file - Add the
*.h
header file with#ifndef
guard - Add the default test template with corresponding name in
tests/test_yourfile.c
Project's Makefile
allows you to, immediatelly without any changes to it, perform:
- Build your binary with the same name as your project in
bin/project
by invokingmake
- Run a Criterion test suite by invoking
make test
- Clean up your build artefacts and start over with invoking
make clean
The Makefile
is universal, one-time statically generated, at project's creation time. That means:
- Unless you do not diverge from source file creation logic, eg. put your
*.c
and*.h
files tosrc/
and its subfolders and put your tests intotests/
(or you do strictly usenewc
for generatig ones), there is no need to change anything in it.Makefile
is universal enough to find its sources and build the thing or run the tests. - When you feel that your
Makefile
needs any alterations or enhancements, feel free to do so, newc will never touch it again, so you can still usenewc
to add your sources to the project.
Grab the newc
script from this repo and copy it anywhere in your $PATH
. If you obtain the file by other means than cloning this repository by invoking https://github.com/bobac/newc.git
, you may probably need to set it executable by issuing chmod a+x newc
.
newc was tested on MacOS X 11.6 (Big Sur) and Ubuntu 18.04 with XCode resp. gcc dev tools installed. The only real dependency is Criterion testing library, which can be obtained at https://github.com/Snaipe/Criterion.
Assume we are in ~/code
directory and want to create our new C project called awsome
.
newc awsome
It will create a directory ~/code/awsome
with following file structure:
awsome
├── .gitignore
├── .newc
├── Makefile
├── README.md
├── bin
├── obj
├── src
│ └── main.c
└── tests
└── bin
At this time, when you cd into the awsome directory, it can build your project by typing make
(and the binary would show as bin/awsome) and the awsome binary would do exactly nothing - it is your turn, programmer! :-)
Staying in awsome/ directory, just issue newc comp.c
and the folder structure will became as follows:
awsome
├── .gitignore
├── .newc
├── Makefile
├── README.md
├── bin
├── obj
├── src
│ ├── comp.c
│ ├── comp.h
│ └── main.c
└── tests
├── bin
└── test_comp.c
You may create sources in subdirectories that logically belongs to each other, you may try to invoke newc unit/par1.c
followed by newc unit/part2.c
. The structure would look like this:
awsome
├── .gitignore
├── .newc
├── Makefile
├── README.md
├── bin
├── obj
│ └── unit
├── src
│ ├── comp.c
│ ├── comp.h
│ ├── main.c
│ └── unit
│ ├── part1.c
│ ├── part1.h
│ ├── part2.c
│ └── part2.h
└── tests
├── bin
│ └── unit
├── test_comp.c
└── unit
├── test_part1.c
└── test_part2.c
Etc, etc, you get the idea.
If you followed above examples, it's now time to use the build system generated by newc. Let's try to run some tests! Issue make test
and you will get the output similar to this:
gcc -Isrc/ -g -Wall -c src/comp.c -o tests/bin/comp.o
gcc -Isrc/ -g -Wall -c src/unit/part1.c -o tests/bin/unit/part1.o
gcc -Isrc/ -g -Wall -c src/unit/part2.c -o tests/bin/unit/part2.o
gcc -I/Users/bobac/code/newc/awsome/src/ -g -Wall tests/bin/comp.o tests/bin/unit/part1.o tests/bin/unit/part2.o tests/test_comp.c -o tests/bin/test_comp -lcriterion
gcc -I/Users/bobac/code/newc/awsome/src/ -g -Wall tests/bin/comp.o tests/bin/unit/part1.o tests/bin/unit/part2.o tests/unit/test_part1.c -o tests/bin/unit/test_part1 -lcriterion
gcc -I/Users/bobac/code/newc/awsome/src/ -g -Wall tests/bin/comp.o tests/bin/unit/part1.o tests/bin/unit/part2.o tests/unit/test_part2.c -o tests/bin/unit/test_part2 -lcriterion
echo TESTBINS= tests/bin/test_comp tests/bin/unit/test_part1 tests/bin/unit/test_part2
TESTBINS= tests/bin/test_comp tests/bin/unit/test_part1 tests/bin/unit/test_part2
for test in tests/bin/test_comp tests/bin/unit/test_part1 tests/bin/unit/test_part2 ; do ./$test ; done
[----] tests/test_comp.c:7: Assertion failed: Default COMP failing test.
[FAIL] COMP::default: (0,00s)
[====] Synthesis: Tested: 1 | Passing: 0 | Failing: 1 | Crashing: 0
[----] tests/unit/test_part1.c:7: Assertion failed: Default UNIT_PART1 failing test.
[FAIL] UNIT_PART1::default: (0,00s)
[====] Synthesis: Tested: 1 | Passing: 0 | Failing: 1 | Crashing: 0
[----] tests/unit/test_part2.c:7: Assertion failed: Default UNIT_PART2 failing test.
[FAIL] UNIT_PART2::default: (0,00s)
[====] Synthesis: Tested: 1 | Passing: 0 | Failing: 1 | Crashing: 0
make: *** [test] Error 1
Don worry about the failing tests, it is OK, the test templates were deliberately generated to contain 1 passing and 1 failing test each - it is your job to do somenthing meaningfull here. But in general - Yikes, it works!
If you want to build your project, nothing easier than invoking make
. If you want to clean your build artefacts, just type make clean
. And that's all folks!
newc
uses only one switch:
-c|--cc <compiler>
sets compiler used by the build system that is placed into the Makefile. Relevant only when creating a new project. It is ignored when adding project sources.
newc -c gcc project1
will create project1
that uses gcc
as compiler.
newc -c clang project2
will create project2
that uses clang
compiler instead.
There are not that many future plans as this was a hobby project for me over couple of evenings and main aim was to decipher a bit cryptic makefiles. I can imagine that I can add a switch that might remove the testsuite generation but not sure whther it worths it - the testing is a really good practice and anyway, if you even do not have your Criterion installed the make file would still work (minus make test
).
Another topic might be adding libraries support and shared libraries support, time will show.
newc
uses .newc
file in the root of the project. The content is not important, it's sole use is for the script to know if it is invoked in a project directory or not. If not, newc something
will create a directory something/
and puts a newly generated project there. If it is in a directory that already contains .newc file, it will add the source(s) into src/
instead and generate their appropriate contents.