Skip to content

Commit

Permalink
?build.sh: incremental builds (reuse objects),
Browse files Browse the repository at this point in the history
	unless called as `./build.sh [--clean || --rebuild]` (or unless source code is more new).
	This reduces average build times an order of magnitude,
	but was too much bloat with list of sources to build (thus replaced lists with loops).
	Is progress to issue #18 (which is almost all about build scripts).
	Is followup to: 35b2387 (?`build.sh`: +`OBJDIR`(+`obj/`), +`BINDIR`(+`bin/`)).
	TODO: since generic code replaced most of this, move the generic code into `./Macros.sh` (or other script suitable to reuse).
	TODO: remove `[` clutter, remove `basename` clutter (`> /dev/null` doesn't fix this).

?`README.md`:
	Misc typo fixes.
	?`Console flags:`: How to put `--clean` (or `--rebuild`) to use.
	?`Files:`: Point out that incremental builds require prefix "Class" for local includes.
	Is followup to 58f4a78 (?`README.md`: ... Fixups: ...).
  • Loading branch information
SwuduSusuwu committed Nov 17, 2024
1 parent 58f4a78 commit 2a6e624
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 28 deletions.
24 changes: 13 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ Targets: Windows/Linux/Android/OSX/iOS; minimum [_C++11_](https://gcc.gnu.org/pr
Usage: [`./build.sh [OPTIONS]`](https://github.com/SwuduSusuwu/SubStack/blob/trunk/build.sh) produces objects (`./obj/*.o`, for distribution into other tools,) plus [_Executable and Linkable Format_](https://wikipedia.org/wiki/Executable_and_Linkable_Format) (`./bin/a.out`, to do examples/[unit tests](https://wikipedia.org/wiki/Unit_test#Agile) which prove how effective functions execute,) both of which you can redirect with `export OBJDIR=___` (or `export BINDIR=___`.)
- [`./cxx/main.hxx`](https://github.com/SwuduSusuwu/SubStack/blob/trunk/cxx/main.hxx) has constants to use to interpret `a.out`'s return values.
- Console flags:
- `./build.sh` : Defaults to `./build.sh --debug`.
- `./build.sh` : Defaults to `./build.sh --debug`. For all source code, if intermediate object doesn't exist or is older than source, builds source.
- `./build.sh --clean` : removes intermediate object files + exits; to reduce disc use.
- `./build.sh --rebuild` : removes intermediate object files + continues; to rebuild with new flags (or if `./build.sh` doesn't rebuild code which includes updated headers).
- `./build.sh --debug` : includes frame-pointers/debug symbols (`-g`), includes `valgrind`-replacement tools (such as `-fsanitize=address`), optimizes with `-Og`.
- `./build.sh --release` : excludes `--debug` (`-DNDEBUG`), strips frame-pointers/symbols, optimizes with `-O2`.
- `./build.sh --mingw` : can mix with `--release` or `--debug`. Produces [_Portable Executable_](https://wikipedia.org/wiki/Portable_Executable) (`./bin/a.exe`), for _Windows_
- `./build.sh --mingw` : can mix with `--release` or `--debug`. Produces [_Portable Executable_](https://wikipedia.org/wiki/Portable_Executable) (`./bin/a.exe`), for _Windows_.
- Special flags (`vim build.sh` to use); other than `_PREFER_`/`_SKIP_`, most use more resources if set to `true`:
- Custom `sh` (console) output:
- `-DSUSUWU_SH_PREFER_STDIO` to replace `std::cXXX << ...` with `fprintf(stdXXX, ...)`; default is `!defined(__cplusplus)`.
Expand All @@ -47,28 +49,28 @@ Usage: [`./build.sh [OPTIONS]`](https://github.com/SwuduSusuwu/SubStack/blob/tru
# Contributor conventions/rules
Linter: `clang-tidy cxx/*.cxx` /* uses [`.clang-tidy`](https://github.com/SwuduSusuwu/SubStack/blob/trunk/.clang-tidy) options */
## Git
Do atomic commits: Commits should allow to use `git rebase -i` to reorder, unless commit messages include such as "Is followup to \<commit hash\>" (which shows temporal order).
Do atomic commits: if you cannot `./build.sh` your commit if it is swapped (such as through `git rebase -i`) with a previous commit, or cannot `./build.sh` if a previous commit got `git revert`, your commit message must include such as "Is followup to \<commit hash\>" (which shows temporal order).

`git commit` message format/syntax:
- if commit does `git add NewFile`: message has `+\`NewFile\``
- if `git rm Exists`: `-`Exists``
- if `touch Exists && git add Exists`: `@\`Exists\`` or `?\`Exists\``
- Simple wildcards/regex for altered functions: `\`%s/oldFunction/newFunction/\``
- if commit does `git add NewFile`: message has `+\`NewFile\``.
- if `git rm Exists`: `-`Exists``.
- if `touch Exists && git add Exists`: `@\`Exists\`` or `?\`Exists\``.
- Simple wildcards/regex for altered functions: `\`%s/oldFunction/newFunction/\``.
- if `echo "int newFunction() {...}" >> Exists && git add Exists`: `@\`Exists\`:+\`NewFunction()\``.
- if `git mv OldPath/ NewPath/`: `\`OldPath/.* -> NewPath/.*\``
- if `git mv OldPath/ NewPath/`: `\`OldPath/.* -> NewPath/.*\``.

[Notice: Commit titles can omit backticks (``) if not enough room; the backticks just allow _GitHub_ to format code/paths.]
## Source
Most of what [_Mozilla Org_'s (_Firefox_'s) style](https://firefox-source-docs.mozilla.org/code-quality/coding-style/coding_style_cpp.html) suggests is sound (you should follow this unless you have specific reasons not to).
Code rules (lots overlap with _Mozilla Org_'s):

- Files: `#import "PascalCase.hxx"`, as this is most common.
- Files: `#include "PascalCase.hxx"`, as this is most common. `./build.sh` requires: that all local includes prefix as `Class*.hxx` (so it knows to execute `--rebuild` if you upgrade a common include.) TODO: incremental builds which don't require this.

- Structs, enums, classe: `typedef struct PascalCase {} PascalCase;`, `typedef enum PascalCase {} PascalCase;`, `typedef class PascalCase {} PascalCase;`, as this is most common.

- Macros: `#define NAMESPACE_CONSTANT_CASE(snake_case_param) assert(snake_case_param);`, as this is most common.

- Indent: tabs ('^I', reduced memory use, allows local configs to set width, allows arrow keys to move fast); as much tabs as braces ('{', '}'). [All which conflicts with _Mozilla Org_'s format is tab use]
- Indent: tabs ('^I', reduced memory use, allows local configs to set width, allows arrow keys to move fast); as much tabs as braces ('{', '}'). [All which conflicts with _Mozilla Org_'s format is tab use.]

- Braces, functions; most common form:
```
Expand Down Expand Up @@ -106,7 +108,7 @@ const /* const prevents `if(func() = x)` where you wished for `if(func() == x)`
bool functionDeclaration(std::string input, std::deque<vector> output);
```
- It is arguable whether or not you should document such possible system errors; almost all Standard Template Library functions can throw derivatives of `std::logic_error`.
- Regex `:%s/@pre (.*) @code (.*) @endcode/[[expects: \2]] \\* \1 \\*/` `:%s/@post (.*) @code (.*) @endcode/[[ensures: \2]] \\* \1 \\*/` once have _Contracts_/_C++26_
- Regex `:%s/@pre (.*) @code (.*) @endcode/[[expects: \2]] \\* \1 \\*/` `:%s/@post (.*) @code (.*) @endcode/[[ensures: \2]] \\* \1 \\*/` once have _Contracts_/_C++26_.
- cxx/Macros.cxx has `ASSUME(X)`, which is close to `[[expects: x]]`, but `ASSUME(X)` goes to `*.cxx`, whereas `[[expects]]` goes to `*.hxx`.
- Documentation of interfaces belongs to `*.hxx`; `*.cxx` is to do implementations. Do not duplicate interface comments.
- Advantages of `[[expects]]`; allows to move information of interfaces out of `*.cxx`, to `*.hxx`.
Expand Down
66 changes: 49 additions & 17 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ CXXFLAGS_FSAN="-fsanitize=address -fno-sanitize-recover=all -fsanitize=float-div
#CXXFLAGS_FSAN="${CXXFLAGS_FSAN} -fsanitize=undefined" #/* causes 'cannot locate symbol "__ubsan_handle_function_type_mismatch_abort"' */

CROSS_COMP=""
if [ "--mingw" = "${1}" ] || [ "--mingw" = "${2}" ]; then
if [ "--mingw" = "${1}" -o "--mingw" = "${2}" ]; then
CROSS_COMP=" --mingw"
LDFLAGS="${LDFLAGS} -static-libgcc -static-libstdc++"
if command -v x86_64-w64-mingw32-clang++ > /dev/null; then
Expand All @@ -41,7 +41,7 @@ else
exit 1
fi

if [ "--release" = "${1}" ] || [ "--release" = "${2}" ]; then
if [ "--release" = "${1}" -o "--release" = "${2}" ]; then
SUSUWU_PRINT "${SUSUWU_SH_NOTICE}" "\`${0}${CROSS_COMP} --release\` does not support profilers/debuggers (use \`${0}${CROSS_COMP} --debug\` for this)."
CXXFLAGS="${CXXFLAGS} ${CXXFLAGS_RELEASE}"
else
Expand Down Expand Up @@ -79,30 +79,62 @@ else
SUSUWU_PRINT "${SUSUWU_SH_NOTICE}" "\`${LD} ... -o \${BINDIR}${OUTPUT}\` inherits local \`BINDIR=\"${BINDIR}\"\` until you execute \`unset BINDIR\`."
fi
mkdir -p "${OBJDIR}" "${BINDIR}"
if [ "--rebuild" = "${1}" -o "--rebuild" = "${2}" ]; then
SUSUWU_PRINT "${SUSUWU_SH_NOTICE}" "Was called with \`${0}${CROSS_COMP} --rebuild\`, will remove intermediate objects+ continue."
rm ${OBJDIR}*.o
fi
if [ "--clean" = "${1}" -o "--clean" = "${2}" ]; then
SUSUWU_PRINT "${SUSUWU_SH_NOTICE}" "Was called with \`${0}${CROSS_COMP} --clean\`, will remove intermediate objects + exit. Use \`${0}${CROSS_COMP} --rebuild\` to clean + continue."
rm ${OBJDIR}*.o
exit 0
fi

C_SOURCE_PATH=$(SUSUWU_DIR_SUFFIX_SLASH "${C_SOURCE_PATH}") #/* if inherit C_SOURCE_PATH, perhaps it lacks '/' */
CXX_SOURCE_PATH=$(SUSUWU_DIR_SUFFIX_SLASH "${CXX_SOURCE_PATH}") #/* if inherit CXX_SOURCE_PATH, perhaps it lacks '/' */
OBJDIR=$(SUSUWU_DIR_SUFFIX_SLASH "${OBJDIR}") #/* if inherit OBJDIR, perhaps it is without last '/' */
BINDIR=$(SUSUWU_DIR_SUFFIX_SLASH "${BINDIR}") #/* if inherit BINDIR, perhaps it is without last '/' */
if [ -e ${BINDIR}${OUTPUT} ]; then
BUILDNEW=false
else
BUILDNEW=true
fi
for SOURCE in ${CXX_SOURCE_PATH}Class*.hxx ${CXX_SOURCE_PATH}Macros.hxx; do
OBJECT="${OBJDIR}$(basename ${SOURCE} .hxx).o" #/* `basename`'s second param removes suffix */
SRCCXX="${CXX_SOURCE_PATH}$(basename ${SOURCE} .hxx).cxx" #/* `basename`'s second param removes suffix */
if [ ${OBJECT} -ot ${SOURCE} -a -e ${SOURCE} ]; then #/* `&& [ -e ${SOURCE} ]` is: skip unless `${SOURCE}` exists. */
SUSUWU_PRINT "${SUSUWU_SH_NOTICE}" "\`${SOURCE}\` is newer than \`${OBJECT}\`, will rebuild all objects."
rm ${OBJDIR}*.o
break
elif [ ! -e ${SRCCXX} ]; then #/* If `*.hxx` doesn't have `*.cxx` match, */
touch ${OBJECT}; #/* ... then produce `*.o` (for future tests.) */
fi
done
OBJECTLIST=""
set -x
${CC} ${CCFLAGS} -c "${C_SOURCE_PATH}rfc6234/sha1.c" -o "${OBJDIR}sha1.o"
${CC} ${CCFLAGS} -c "${C_SOURCE_PATH}rfc6234/sha224-256.c" -o "${OBJDIR}sha224-256.o"
${CC} ${CCFLAGS} -c "${C_SOURCE_PATH}rfc6234/sha384-512.c" -o "${OBJDIR}sha384-512.o"
${CXX} ${CXXFLAGS} -c "${CXX_SOURCE_PATH}Macros.cxx" -o "${OBJDIR}Macros.o"
${CXX} ${CXXFLAGS} -c "${CXX_SOURCE_PATH}ClassSha2.cxx" -o "${OBJDIR}ClassSha2.o"
${CXX} ${CXXFLAGS} -c "${CXX_SOURCE_PATH}ClassResultList.cxx" -o "${OBJDIR}ClassResultList.o"
${CXX} ${CXXFLAGS} -c "${CXX_SOURCE_PATH}ClassSys.cxx" -o "${OBJDIR}ClassSys.o"
${CXX} ${CXXFLAGS} -c "${CXX_SOURCE_PATH}ClassCns.cxx" -o "${OBJDIR}ClassCns.o"
${CXX} ${CXXFLAGS} -c "${CXX_SOURCE_PATH}VirusAnalysis.cxx" -o "${OBJDIR}VirusAnalysis.o"
${CXX} ${CXXFLAGS} -c "${CXX_SOURCE_PATH}AssistantCns.cxx" -o "${OBJDIR}AssistantCns.o"
${CXX} ${CXXFLAGS} -c "${CXX_SOURCE_PATH}main.cxx" -o "${OBJDIR}main.o"
#/* Order is 2 fold: language of code, plus which source the most `#include` (most include `Macros.hxx`). */
${LD} ${LDFLAGS} "${OBJDIR}sha1.o" "${OBJDIR}sha224-256.o" "${OBJDIR}sha384-512.o" "${OBJDIR}Macros.o" "${OBJDIR}ClassSha2.o" "${OBJDIR}ClassResultList.o" "${OBJDIR}ClassSys.o" "${OBJDIR}ClassCns.o" "${OBJDIR}VirusAnalysis.o" "${OBJDIR}AssistantCns.o" "${OBJDIR}main.o" -o "${BINDIR}${OUTPUT}"
#for SOURCE in ${C_SOURCE_PATH}*/*.c; do #/* The extra "*/" is since this just has vendored code (`rfc6234/`) */
for SOURCE in "${C_SOURCE_PATH}rfc6234/sha1.c" "${C_SOURCE_PATH}rfc6234/sha224-256.c" "${C_SOURCE_PATH}rfc6234/sha384-512.c"; do
OBJECT="${OBJDIR}$(basename ${SOURCE} .c).o" #/* `basename`'s second param removes suffix */
if [ ${OBJECT} -ot ${SOURCE} -o ! -e ${OBJECT} ] >/dev/null; then
${CC} ${CCFLAGS} -c "${SOURCE}" -o "${OBJECT}"
BUILDNEW=true
fi
OBJECTLIST="${OBJECTLIST} ${OBJECT}"
done
for SOURCE in ${CXX_SOURCE_PATH}*.cxx; do
OBJECT="${OBJDIR}$(basename ${SOURCE} .cxx).o" #/* `basename`'s second param removes suffix */
if [ ${OBJECT} -ot ${SOURCE} -o ! -e ${OBJECT} ] > /dev/null 2>&1; then
${CXX} ${CXXFLAGS} -c "${SOURCE}" -o "${OBJECT}"
BUILDNEW=true
fi
OBJECTLIST="${OBJECTLIST} ${OBJECT}"
done
${BUILDNEW} && ${LD} ${LDFLAGS}${OBJECTLIST} -o "${BINDIR}${OUTPUT}"
STATUS=$?
set +x

if [ 0 -eq ${STATUS} ]; then
SUSUWU_PRINT "${SUSUWU_SH_SUCCESS}" "produced \`${BINDIR}${OUTPUT}\` (`stat -c%s ${BINDIR}${OUTPUT}` bytes)."
if [ 0 -eq ${STATUS} -o false = ${BUILDNEW} ]; then
${BUILDNEW} && SUSUWU_PRINT "${SUSUWU_SH_SUCCESS}" "produced \`${BINDIR}${OUTPUT}\` (`stat -c%s ${BINDIR}${OUTPUT}` bytes)."
${BUILDNEW} || SUSUWU_PRINT "${SUSUWU_SH_SUCCESS}" "reused \`${BINDIR}${OUTPUT}\` (`stat -c%s ${BINDIR}${OUTPUT}` bytes)."
BINDIR=$(SUSUWU_DIR_AFFIX_DOTSLASH "${BINDIR}")
${BINDIR}${OUTPUT}
STATUS=$?
Expand Down

0 comments on commit 2a6e624

Please sign in to comment.