This is a template intended for multi-purpose C projects, that can easily be modified for C++.
Clone the repo :
git clone https://github.com/Bitwise-re/c-template.gitOr using ssh :
git clone git@github.com:Bitwise-re/c-template.gitThen delete history :
rm -r .git
git initTip
You can also click on use this template on the repo page to create a new repo based on this template.
/
├── .github/
| └── workflows
| ├── build.yml
| ├── deploy.yml
| └── test.yml
├── bin/
├── build/
| ├── assets/
| ├── linux/
| └── windows/
├── scripts/
| ├── createnode.sh
| └── getnodes.sh
├── src/
│ └── app/
| ├── main.c
| └── flags.gcc
├── temp/
├── templates/
| ├── lib.c
| ├── lib.h
| ├── main.c
| └── onode.mk
├── test/
├── LICENSE
├── Makefile
├── README.md
└── vars.mk
.github/: Holds the repo files (workflows, issue templates, ...).bin/: Holds the binaries created by make (.exe, .dll, .dll.a, .so, ...).build: Holds the final product in the directory corresponding to the os used to build. The assets folder holds static files common to all os.scripts: Holds the different shell scripts used by makefile.src: Holds the source code organized in nodes.temp: Holds temporary files used for developping without risking them to be uploaded to the repo.templates: Holds templates for the script to create nodestest: Holds the testfiles use for quick tests like syntax or linking.LICENSE: The project's licenseMakefile: The main makefile, contains the recipes for the projectvars.mk: The project's makefile containing all variables and functions, can be safely imported by other makefiles (in other nodes for instance)
The source folder is structured by nodes, there are 3 types of node :
-
Other node
Other nodes are custom nodes holding their own Makefile which should include 3 specific variables :
__FILES-> holds the files built by this node.
__DEPS-> holds the files on which depend the files above.
__IMPL_LINK-> How to implement the node's files in the linking step of another file which depend on those files.
A node containing a Makefile is processed as an Other node. -
Executable node
Executable nodes hold the source code for an executable. A node containing a main.c file is processed as an Executable node. -
Library node
Library nodes are holding source code for shared libraries (.dllon windows and.soon linux). Any node which isn't an Executable node nor an Other node is processed as a Library node.
There are 2 main Makefiles in this template : ./Makefile wich holds the recipes and ./vars.mk which holds all structure related variables as well as functions for the recipes.
Project structure, extensions used and flags for each step of the build chain can be found in ./vars.mk.
Tip
While the flags for each step of the build chain are the same for every node, you can add flags for the linking step by adding them in {step_id}.flags, where step_id can be found in ./vars.mk.. Each flags with the prefix W_ will be used for windows builds and L_ for linux builds.
To add an executable, just create a new subfolder in ./src/containing a main.c file.
Same for adding a file with custom build process : just create a new subfolder in ./src/ containing a Makefile.
To add a library, create a new subfolder in ./src/ with source code in it.
To add ressources/assets to be directly inserted in the final product's root folder, put them in ./build/assets.
Tip
To add new nodes, the main Makefile provides recipes :
| Node Type | Command |
|---|---|
| Executable | make __ne_{node_name} |
| Library | make __nl_{node_name} |
| Other | make __no_{node_name} |
flowchart TD;
START((make build)) --> RC@{ shape: procs, label: "Clean/Reset"}
RC --> MKA@{ shape: procs, label: "make all" }
MKA --> CLN@{ shape: procs, label: "Clean" }
CLN --> CPB@{ shape: proc, label: "Copy binaries to build folder" }
CPB --> CLI@{ shape: proc, label: "Remove import libraries from build folder" }
CLI --> CPA@{ shape: proc, label: "Copy assets to build folder" }
CPA --> CLB@{ shape: proc, label: "Empty bin folder" }
CLB --> END@{ shape: double-circle, label: "Done" }
CLN -..-> RCG_CLN@{ shape: f-circ, label: "Clean" }
subgraph RCG [ Clean/Reset ]
RCG_START((make cr)) --> RCG_BIN@{ shape: proc, label: "Empty bin directory" }
RCG_BIN --> RCG_BLD@{ shape: proc, label: "Empty build directory" }
RCG_BLD --> RCG_CLN
RCG_CLN --> RCG_FEN@{ shape: hex, label: "For each Executable and Library node" }
RCG_FEN -->|Next| RCG_DLD@{ shape: proc, label: "Delete dependency files" }
RCG_DLD --> RCG_DLI@{ shape: proc, label: "Delete pre-processor files" }
RCG_DLI --> RCG_DLA@{ shape: proc, label: "Delete assembly files" }
RCG_DLA --> RCG_DLO@{ shape: proc, label: "Delete object files" }
RCG_DLO --> RCG_FEN
RCG_FEN ---->|Done| RCG_FEON@{ shape: hex, label: "For each Other node" }
RCG_FEON -->|Next| RCG_CON@{ shape: procs, label: "Execute 'make clean' in the node" }
RCG_CON --> RCG_FEON
RCG_FEON -->|Done| RCG_END@{ shape: double-circle, label: "Done" }
end
subgraph MKA_G [ make all ]
MKA_START((make all)) --> MKA_FEN@{ shape: hex, label: "For each Node" }
MKA_FEN -->|Next| MKA_INO@{ shape: diamond, label: "Is it an Other node ?" }
MKA_INO -->|Yes| MKA_BON@{ shape: procs, label: "Build Other node" }
MKA_INO -->|No| MKA_BDN@{ shape: procs, label: "Build Executable/Library node" }
MKA_FEN ---->|Done| MKA_END@{ shape: double-circle, label: "Done" }
subgraph MKO [ Build an Other node ]
MKO_START(("make %")) --> MKO_GTN@{ shape: proc, label: "Get associated node" }
MKO_GTN --> MKO_GTD@{ shape: proc, label: "Get dependencies from the node's Makefile" }
MKO_GTD --> MKO_BDD@{ shape: procs, label: "Build dependencies" }
MKO_BDD --> MKO_BLD@{ shape: procs, label: "Execute 'make %' in the node" }
MKO_BLD --> MKO_END@{ shape: double-circle, label: "Done" }
end
subgraph MKN [ Build a Library/Executable node ]
MKN_START(("make %(.exe) / %.so(.dll)")) --> MKN_GTN@{ shape: proc, label: "Get associated node" }
MKN_GTN --> MKN_FEF@{ shape: hex, label: "For each source file (.c)" }
MKN_FEF -->|Next| MKN_CDF@{ shape: proc, label: "Create dependency file" }
MKN_CDF --> MKN_CIF@{ shape: proc, label: "Create pre-processor file" }
MKN_CIF --> MKN_CAF@{ shape: proc, label: "Create assembly file" }
MKN_CAF --> MKN_COB@{ shape: proc, label: "Create object file" }
MKN_COB --> MKN_FEF
MKN_FEF -->|Done| MKN_DEP@{ shape: proc, label: "Get dependencies from the node's dep files" }
MKN_DEP --> MKN_BDD@{ shape: procs, label: "Build dependencies" }
MKN_BDD --> MKN_LNK@{ shape: proc, label: "Link object files and dependencies into %" }
MKN_LNK --> MKN_END@{ shape: double-circle, label: "Done" }
end
MKA_BON -..-> MKO_START
MKA_BDN -..-> MKN_START
MKO_BDD -..-> MKA_START
MKN_BDD -..-> MKA_START
MKN_END -..-> MKA_FEN
MKO_END -..-> MKA_FEN
end
RC -..-> RCG_START
MKA -..-> MKA_START
This templates comes with Github Workflows.
- Test : Triggered on PR, used to verify modifications to important branches does not bring bugs. Passes the code through a series of tests, including the whole buildling process, in different environnements.
- Build : Triggered on demand by other workflows, covers the whole building process for the linux and windows app.
- Deploy : Triggered by a push on the main branch, calls the build process and package the output into a release.
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
Caution
Please make sure to update tests as appropriate.
This project is under GNU 3 License