Skip to content

Latest commit

 

History

History
258 lines (203 loc) · 8.44 KB

tutorial.md

File metadata and controls

258 lines (203 loc) · 8.44 KB

Tutorial

This tutorial will take you from a new github project and provide a good overview of the nobuild framework, with real examples.

If you don't already have a repository cloned or created locally. Follow this guide. Github

Start

Copy the ./nobuild.h file found at the root of this repository nobuild.h to the root of your repository.

Copy the starter ./demo/nobuild.c file found in this demo folder nobuild.c to the root of your repository.

  • the demo contents should appear as follows.

./nobuild.c

#define NOBUILD_IMPLEMENTATION
#define CFLAGS "-Wall", "-Werror", "-std=c11"
#include "./nobuild.h"

int main(int argc, char **argv) {
  BOOTSTRAP(argc, argv);
  return 0;
}
  • if you wish to use a different compiler you can add another line #define CC "clang"

The file structure should appear as below.

> ls -a
.git
.gitignore
LICENSE
README.md
nobuild.h
nobuild.c
  • you may or may not have the LICENSE, .gitignore, and README depending on if you initialized your own git repo, or did it through github in the browser.

Build nobuild

Build nobuild. You will have to do this any time, you modify your ./nobuild.c file!

> gcc ./nobuild.c -o ./nobuild

Initialize your repository as a nobuild project.

> ./nobuild --init
[INFO] MKDIRS: target/nobuild
[INFO] MKDIRS: obj
[INFO] MKDIRS: exes
[INFO] MKDIRS: src
[INFO] MKDIRS: tests
[INFO] MKDIRS: include
  • this created a few directories.
    • src will contain all your c source files.
    • tests will contain all your test files.
    • obj will contain all your object files generated by your C Compiler.
    • exes will contain all your source c files that become executables.
    • target will contain all your deliverable or meaningful deployments. Binaries, shared libraries, static libraries, tests, etc.
    • include will contain all your include files.

Adding features

Add your first feature.

> ./nobuild --add hello
[INFO] MKDIRS: include
[INFO] CMD: touch include/hello.h
[INFO] MKDIRS: src/hello
[INFO] CMD: touch src/hello/lib.c
[INFO] MKDIRS: tests
[INFO] CMD: touch tests/hello.c
  • this created a new folder in the src directory, a test file, an include file, and an empty c file.
  • you will notice that the output has a lot of the same information when we ran --init. This is because we are being safe and making sure that those folders exist, if not, they are created. We can suppress [INFO] logs by adding #define NOINFO at the top of our nobuild.c file.

Modify your ./nobuild.c accordingly. Use your editor of choice.

./nobuild.c

#define NOBUILD_IMPLEMENTATION
#define CFLAGS "-Wall", "-Werror", "-std=c11"
// optionally define NOINFO, all info logs will be present in the tutorial
#define NOINFO
#include "./nobuild.h"

int main(int argc, char **argv) {
  FEATURE("hello"); // only required line for this step of tutorial.
  BOOTSTRAP(argc, argv);
  return 0;
}
  • sometimes, you might have additional dependencies defined outside of the project like sdl2 or boost or much more commonly, pthread. nobuild doesn't add this FEATURE automatically to nobuild.c. (maybe future releases).
    • here is where you would add extra linking dependencies. FEATURE("hello","-lpthread");. This is saying: any time you build a deployable, that uses hello, you need to have pthread linked with it.
  • run gcc ./nobuild.c -o ./nobuild. I have a simple key press combo bound to do this in my editor. You can do similar in your editor.

Run ./nobuild

> ./nobuild
[WARN] No arguments passed to nobuild
[WARN] Building all features
[INFO] MKDIRS: target/nobuild
[INFO] MKDIRS: obj
[INFO] MKDIRS: obj/hello
[INFO] CMD: gcc -Wall -Werror -std=c11 -g -O0 -fPIC -o obj/hello/lib.o -c src/hello/lib.c
[INFO] CMD: gcc -Wall -Werror -std=c11 -g -O0 -o target/hello tests/hello.c obj/hello/lib.o
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o: in function `_start':
(.text+0x24): undefined reference to `main'
collect2: error: ld returned 1 exit status
[ERRO] command exited with exit code 1
  • you will get errors from your compiler if your code has an issue. This issue here, is describing how the tests/hello.c file does not have a main function.

Finally, some code

Update your include file, library file, and test file.

./include/hello.h

#pragma once

int show_hello();

./src/hello/lib.c

#include <stdio.h>

int show_hello() {
  puts("Hello"); 
  return 0;
}

./tests/hello.c

#define NOBUILD_IMPLEMENTATION
#include "../include/hello.h"
#include "../nobuild.h"
#include <stdio.h>

void test_add() { ASSERT(2 + 2 == 4); }

int main() {
  DESCRIBE("hello");
  SHOULDF("add 2 + 2", test_add);
  SHOULDB("compare two strings", { ASSERT_STR_EQ("hello", "hello"); });
  RETURN();
}

Run ./nobuild --release or ./nobuild -r. All commands come with a short flag.

> ./nobuild -r
[INFO] MKDIRS: target/nobuild
[INFO] MKDIRS: obj
[INFO] MKDIRS: obj/hello
[INFO] CMD: gcc -Wall -Werror -std=c11 -O3 -fPIC -o obj/hello/lib.o -c src/hello/lib.c
[INFO] CMD: gcc -Wall -Werror -std=c11 -O3 -o target/hello tests/hello.c obj/hello/lib.o
[INFO] CMD: target/hello
[INFO] DESCRIBE: tests/hello.c => hello
      [RUN!] It should... add 2 + 2
      [OKAY] Passed
      [RUN!] It should... compare two strings
      [OKAY] Passed
[INFO] NOBUILD took ... 0.000370 sec
[INFO] OKAY: tests passed 2
[INFO] FAIL: tests failed 0
[INFO] TOTAL: tests ran 2
  • success!. ./nobuild with no arguments will assume you want the debug version. You can be explicit with ./nobuild -d
  • SHOULDB takes an inline body, SHOULDF takes a function name. Allowing you to break up your code and better read the flow in main.
  • We can run and debug our tests, independently. All tests are created as an executable, try it. ./target/hello. If you wanted debug symbols included, run nobuild with the debug flag. ./nobuild -d

Packaging shared libraries and making executables

Right now, our hello feature, is just an object file. Let's make it an executable and a shared library. This will allow others to execute our amazing hello program, or use hello as a library in their own project.

> ./nobuild --exe holler
[INFO] MKDIRS: exes
[INFO] CMD: touch exes/holler.c

./exes/holler.c

#include "../include/hello.h"

int main() { 
  show_hello();
}

./nobuild.c

#define NOBUILD_IMPLEMENTATION
#define CFLAGS "-Wall", "-Werror", "-std=c11"
#include "./nobuild.h"

int main(int argc, char **argv) {
  FEATURE("hello");
  LIB("hello");
  EXE("holler", "hello");
  BOOTSTRAP(argc, argv);
  return 0;
}
  • after running gcc ./nobuild.c -o ./nobuild. You can run ./nobuild once again.
> ./nobuild -d
[INFO] MKDIRS: target/nobuild
[INFO] MKDIRS: obj
[INFO] MKDIRS: obj/hello
[INFO] CMD: gcc -Wall -Werror -std=c11 -g -O0 -fPIC -o obj/hello/lib.o -c src/hello/lib.c
[INFO] CMD: gcc -Wall -Werror -std=c11 -g -O0 -shared -o target/libhello.so obj/hello/lib.o
[INFO] CMD: gcc -Wall -Werror -std=c11 -g -O0 -o target/hello tests/hello.c obj/hello/lib.o
[INFO] CMD: target/hello
[INFO] DESCRIBE: tests/hello.c => hello
      [RUN!] It should... add 2 + 2
      [OKAY] Passed
      [RUN!] It should... compare two strings
      [OKAY] Passed
[INFO] CMD: gcc -Wall -Werror -std=c11 -g -O0 -o target/holler exes/holler.c obj/hello/lib.o
[INFO] NOBUILD took ... 0.000564 sec
[INFO] OKAY: tests passed 2
[INFO] FAIL: tests failed 0
[INFO] TOTAL: tests ran 2
  • we now have an executable which works exactly like we expected. Run it with ./target/holler
  • we also have a library that was placed in target. Distribute it to all your friends.
  • !NOTE! as of right now, if your exe has the same name as a feature. that features tests can't be ran independently.

Complete?

The bulk of the tutorial is complete. This may seem a bit much. I rely on shortcuts in my editor to accomplish everything without any thought. see the demo in vim or vscode to get an idea how painless using nobuild is. See a complete list of options to read up on all commands, macros, and flags possible. For preparing your code to production see cicd

The next part of the tutorial will cover the coolest feature in nobuild the incremental build.

Incremental