/newc

short c project generator script

Primary LanguageShellBSD Zero Clause License0BSD

newc

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

What you get

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:

  1. Add the *.c file
  2. Add an #include directive to include its prototypes from corresponding header file
  3. Add the *.h header file with #ifndef guard
  4. 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:

  1. Build your binary with the same name as your project in bin/project by invoking make
  2. Run a Criterion test suite by invoking make test
  3. 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:

  1. Unless you do not diverge from source file creation logic, eg. put your *.c and *.h files to src/ and its subfolders and put your tests into tests/ (or you do strictly use newc 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.
  2. 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 use newc to add your sources to the project.

Installation

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.

Dependencies

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.

Usage

Create a new project

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.

Using the genarated build system

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!

Command-line switches

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.

Examples

newc -c gcc project1 will create project1 that uses gcc as compiler.

newc -c clang project2 will create project2 that uses clang compiler instead.

ToDo

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.

Note

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.