sheepy

build system (sheepy) and package manager (spm) for C
git clone https://spartatek.se/git/sheepy.git
Log | Files | Refs | README | LICENSE

commit 46eb3e390e247e4023d8e342fd2e1e0ca00d5b5a
parent d23ef903511b9dd8bc635b468cb7ea39052850cc
Author: Remy Noulin <loader2x@gmail.com>
Date:   Fri,  3 Jan 2020 13:35:01 +0100

add asan support

src/common.c |   6 ++-
src/common.h |  37 ++++++++++++++---
src/sheepy.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++-------------
src/sheepy.h |  20 +++++----
src/spm.c    | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++-
src/spm.h    |   4 ++
6 files changed, 267 insertions(+), 44 deletions(-)

Diffstat:
Msrc/common.c | 6++++--
Msrc/common.h | 37+++++++++++++++++++++++++++++++------
Msrc/sheepy.c | 129++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Msrc/sheepy.h | 20+++++++++++++-------
Msrc/spm.c | 115+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/spm.h | 4++++
6 files changed, 267 insertions(+), 44 deletions(-)

diff --git a/src/common.c b/src/common.c @@ -150,13 +150,15 @@ void pkgFromTemplate(const char *pkgname) { char *testname = dupG(pkgname);; toUpper(testname[0]); char *memcheckname = dupG(testname);; + char *asanname = dupG(testname);; iPrependS(&testname, "test"); iPrependS(&memcheckname, "memcheck"); + iPrependS(&asanname, "asan"); - char *t = replaceManyS(PKG_TEMPLATE, "<PKG_NAME>", pkgname, "<TEST_NAME>", testname, "<MEMCHECK_NAME>", memcheckname);; + char *t = replaceManyS(PKG_TEMPLATE, "<PKG_NAME>", pkgname, "<TEST_NAME>", testname, "<MEMCHECK_NAME>", memcheckname, "<ASAN_NAME>", asanname);; writeFileG(t, PACKAGE); - freeManyS(testname, memcheckname, t); + freeManyS(testname, memcheckname, asanname, t); } /** diff --git a/src/common.h b/src/common.h @@ -49,10 +49,15 @@ " testLinkWithGold: true\n"\ " #testCflagsAlways: # these flags will always be present, independent of package.yml\n"\ " # The memcheck* are the options for building the memory leak tests (sheepy -m, memcheckBin in package.yml)\n"\ - " memcheckCmd: valgrind --leak-check=full --show-leak-kinds=all\n"\ + " memcheckCmd: valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=1\n"\ " memcheckCflags: -g3 -std=gnu11 -fPIC -pipe # these flags are overriden by package.yml\n"\ " memcheckLflags: -rdynamic # these flags are overriden by package.yml\n"\ " memcheckLinkWithGold: true\n"\ + " # The asan* are the options for building the libsasan tests (sheepy -a, asanBin in package.yml)\n"\ + " asanCmd: env ASAN_OPTIONS=\"detect_leaks=1:detect_stack_use_after_return=1:halt_on_error=0:log_path=stdout:color=always:print_cmdline=1\"\n"\ + " asanCflags: -fsanitize=address -fno-omit-frame-pointer -fsanitize-recover=address # these flags are overriden by package.yml\n"\ + " asanLflags: -rdynamic -fsanitize=address -lasan # these flags are overriden by package.yml\n"\ + " asanLinkWithGold: true\n"\ " key: uninitialized" #define CONFIG_YML_NO_GOLD "---\n"\ @@ -74,10 +79,15 @@ " testLinkWithGold: false\n"\ " #testCflagsAlways: # these flags will always be present, independent of package.yml\n"\ " # The memcheck* are the options for building the memory leak tests (sheepy -m, memcheckBin in package.yml)\n"\ - " memcheckCmd: valgrind --leak-check=full --show-leak-kinds=all\n"\ + " memcheckCmd: valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=1\n"\ " memcheckCflags: -g3 -std=gnu11 -fPIC -pipe # these flags are overriden by package.yml\n"\ " memcheckLflags: -rdynamic # these flags are overriden by package.yml\n"\ " memcheckLinkWithGold: false\n"\ + " # The asan* are the options for building the libsasan tests (sheepy -a, asanBin in package.yml)\n"\ + " asanCmd: env ASAN_OPTIONS=\"detect_leaks=1:detect_stack_use_after_return=1:halt_on_error=0:log_path=stdout:color=always:print_cmdline=1\"\n"\ + " asanCflags: -fsanitize=address -fno-omit-frame-pointer -fsanitize-recover=address # these flags are overriden by package.yml\n"\ + " asanLflags: -rdynamic -fsanitize=address -lasan # these flags are overriden by package.yml\n"\ + " asanLinkWithGold: false\n"\ " key: uninitialized" #define CONFIG_YML_NO_GOLD_ARM "---\n"\ @@ -99,10 +109,15 @@ " testLinkWithGold: false\n"\ " #testCflagsAlways: # these flags will always be present, independent of package.yml\n"\ " # The memcheck* are the options for building the memory leak tests (sheepy -m, memcheckBin in package.yml)\n"\ - " memcheckCmd: valgrind --leak-check=full --show-leak-kinds=all\n"\ + " memcheckCmd: valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=1\n"\ " memcheckCflags: -g3 -std=gnu11 -fPIC -pipe # these flags are overriden by package.yml\n"\ " memcheckLflags: -rdynamic # these flags are overriden by package.yml\n"\ " memcheckLinkWithGold: false\n"\ + " # The asan* are the options for building the libsasan tests (sheepy -a, asanBin in package.yml)\n"\ + " asanCmd: env ASAN_OPTIONS=\"detect_leaks=1:detect_stack_use_after_return=1:halt_on_error=0:log_path=stdout:color=always:print_cmdline=1\"\n"\ + " asanCflags: -fsanitize=address -fno-omit-frame-pointer -fsanitize-recover=address # these flags are overriden by package.yml\n"\ + " asanLflags: -rdynamic -fsanitize=address -lasan # these flags are overriden by package.yml\n"\ + " asanLinkWithGold: false\n"\ " key: uninitialized" #define CONFIG_YML_HAIKU "---\n"\ @@ -124,10 +139,15 @@ " testLinkWithGold: false\n"\ " #testCflagsAlways: # these flags will always be present, independent of package.yml\n"\ " # The memcheck* are the options for building the memory leak tests (sheepy -m, memcheckBin in package.yml)\n"\ - " memcheckCmd: valgrind --leak-check=full --show-leak-kinds=all\n"\ + " memcheckCmd: valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=1\n"\ " memcheckCflags: -g3 -std=gnu11 -fPIC -pipe # these flags are overriden by package.yml\n"\ " memcheckLflags: -rdynamic # these flags are overriden by package.yml\n"\ " memcheckLinkWithGold: false\n"\ + " # The asan* are the options for building the libsasan tests (sheepy -a, asanBin in package.yml)\n"\ + " asanCmd: env ASAN_OPTIONS=\"detect_leaks=1:detect_stack_use_after_return=1:halt_on_error=0:log_path=stdout:color=always:print_cmdline=1\"\n"\ + " asanCflags: -fsanitize=address -fno-omit-frame-pointer -fsanitize-recover=address # these flags are overriden by package.yml\n"\ + " asanLflags: -rdynamic -fsanitize=address -lasan # these flags are overriden by package.yml\n"\ + " asanLinkWithGold: false\n"\ " key: uninitialized" extern char *defaultSpC; @@ -188,11 +208,16 @@ int main(int ARGC, char** ARGV) {\n\ #testBin: ./<TEST_NAME>.c\n\ #testCflags: -g3 -std=gnu11 -fPIC -pipe -fprofile-arcs -ftest-coverage -Wall -Wextra\n\ #testLflags: -lcheck_pic -lrt -lm -lsubunit -fprofile-arcs -ftest-coverage -rdynamic\n\ - # Memcheck configuration:\n\ + # Memcheck configuration (sheepy -m):\n\ #memcheckBin: ./<MEMCHECK_NAME>.c\n\ - #memcheckCmd: valgrind --leak-check=full --show-leak-kinds=all\n\ + #memcheckCmd: valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=1\n\ #memcheckCflags: -g3 -std=gnu11 -fPIC -pipe\n\ #memcheckLflags: -rdynamic\n\ + # The asan* are the options for building the libsasan tests (sheepy -a):\n\ + #asanBin: ./<ASAN_NAME>.c\n\ + #asanCmd: env ASAN_OPTIONS=\"detect_leaks=1:detect_stack_use_after_return=1:halt_on_error=0:log_path=stdout:color=always:print_cmdline=1\"\n\ + #asanCflags: -fsanitize=address -fno-omit-frame-pointer -fsanitize-recover=address # these flags are overriden by package.yml\n\ + #asanLflags: -rdynamic -fsanitize=address -lasan # these flags are overriden by package.yml\n\ #documentationCmd: # command for generating the documentation with spm doc\n\ private: false # true for private package\ " diff --git a/src/sheepy.c b/src/sheepy.c @@ -179,6 +179,8 @@ int MAIN(int ARGC, char** ARGV) { sheepyParams.test = 0; sheepyParams.memcheck = 0; sheepyParams.libsheepyMemcheck = 0; + sheepyParams.asan = 0; + sheepyParams.libsheepyAsan = 0; sheepyParams.new = 0; sheepyParams.showExe = 0; sheepyParams.removeBuild = 0; @@ -294,7 +296,8 @@ int MAIN(int ARGC, char** ARGV) { putsG(" -l (PROGNAME.c) Compile static and dynamic libraries for argument or bin from package"); { putsG(" -d (PROGNAME.c) Delete intermediary files for argument or bin from package"); { putsG(" -t (PROGNAME.c) Compile executable in argument or testBin from package using the test compiler and test linker flags"); - putsG(" -m (PROGNAME.c) Compile executable in argument or memcheckBin from package using the memcheck compiler and memcheck linker flags"); + putsG(" -m (PROGNAME.c) Compile executable in argument or memcheckBin from package using the memcheck compiler and linker flags"); + putsG(" -a (PROGNAME.c) Compile executable in argument or asanBin from package using the asan compiler and linker flags"); putsG(" -n PROGNAME New source program from template"); putsG(" -r Remove all temporary build files in ~/.sheepy/build"); putsG(" -C CLASSNAME Generate C templates for classname (classnames start with lowercase letters, the first char in classname is lowered)"); { @@ -374,6 +377,32 @@ int MAIN(int ARGC, char** ARGV) { dum = argv[2]; } } + else if (eqG(argv[1], "-a")) { + sheepyParams.asan = 1; + sheepyParams.libsheepyAsan = 1; + // check if libsheepyMemAsan exists + dum = catS(libsheepyDir, "/libsheepyAsan.a"); + if (!fileExists(dum)) { + printf("\n" BLD RED "LibsheepyAsan not found: %s not accessible" RST "\nIf libsheepy in another directory, set LIBSHEEPY to libsheepy path, for example: export LIBSHEEPY=/home/$USER/libsheepy/release/\nand compile libsheepyAsan with buildAsan.sh in the libsheepy git repo\n", dum); { + terminateG(bin); + free(dum); + XFAILURE + } + } + freen(dum); + // select main c file + if (bin) { + terminateG(bin); + createSmallJson(packageyml); + readFileG(&packageyml, PACKAGE); + bin = getNDupG(&packageyml, rtSmallStringt, "asanBin"); + freeG(&packageyml); + dum = bin ? ssGet(bin) : argv[2]; + } + else { + dum = argv[2]; + } + } else if (eqG(argv[1], "-n")) { sheepyParams.new = 1; dum = argv[2]; @@ -442,11 +471,15 @@ int MAIN(int ARGC, char** ARGV) { char *s = replaceG(C_TEST_TEMPLATE, "testTemplate", getG(&pkgInfo, rtChar, "name"), 0); writeFileG(s, testBin); free(s); + printf("Generated: "BLD GRN "%s" RST " " UDL "< add the test cases in this file" RST "\n", testBin); + printf("To run the test, execute: " BLD WHT "spm test" RST "\n"); + printf(BLD YLW "Warning" RST ": do not call " UDL "initLibsheepy" RST " in " UDL "%s" RST ", it conflicts with libcheck\n", testBin); - // generate memcheckBin + // generate memcheckBin and asanBin char *memcheckBin = getG(&pkgInfo, rtChar, "memcheckBin"); - if (!memcheckBin) { - putsG(BLD RED "memcheckBin is not set in " UDL PACKAGE RST BLD RED ", add a line with ' memcheckBin: testMem.c'. Memcheck test templates not generated." RST); + char *asanBin = getG(&pkgInfo, rtChar, "asanBin"); + if (!memcheckBin and !asanBin) { + putsG(BLD RED "memcheckBin and asanBin are not set in " UDL PACKAGE RST BLD RED ", add a line with ' memcheckBin: testMem.c' or ' asanBin: testMem.c'. Memcheck test templates not generated." RST); XFAILURE } @@ -455,36 +488,52 @@ int MAIN(int ARGC, char** ARGV) { putsG("Generated: "BLD GRN MEMTEST_C_TEMPLATE_NAME RST); } if (!fileExists(RUNMEMTEST_TEMPLATE_NAME)) { - s = replaceG(RUNMEMTEST_TEMPLATE, "memcheckBin", memcheckBin, 0); - writeFileG(s, RUNMEMTEST_TEMPLATE_NAME); - free(s); + writeFileG(RUNMEMTEST_TEMPLATE, RUNMEMTEST_TEMPLATE_NAME); fileChmod(RUNMEMTEST_TEMPLATE_NAME, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); putsG("Generated: "BLD GRN RUNMEMTEST_TEMPLATE_NAME RST); } - char *shell = NULL; - if (isC(testBin)) { - setG(testBin, -2, 0); - shell = catS(testBin, "Mem.sh"); - // restore original testBin - testBin[strlen(testBin)] = '.'; - if (!fileExists(shell)) { - s = replaceG(MEMCHECK_SH_TEMPLATE, "testBin", testBin, 0); - writeFileG(s, shell); - free(s); - fileChmod(shell, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); - printf("Generated: "BLD GRN "%s" RST"\n", shell); - } + if (memcheckBin) { + char *shell = NULL; + if (isC(testBin)) { + setG(testBin, -2, 0); + shell = catS(testBin, "Mem.sh"); + // restore original testBin + testBin[strlen(testBin)] = '.'; + if (!fileExists(shell)) { + s = replaceManyS(MEMCHECK_SH_TEMPLATE, "testBin", testBin, "memcheckBin", memcheckBin); + writeFileG(s, shell); + free(s); + fileChmod(shell, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); + printf("Generated: "BLD GRN "%s" RST"\n", shell); + } + } + printf("To run the memcheck test, execute: " BLD WHT "%s" RST "\n", shell); + free(shell); + } + if (asanBin) { + char *shell = NULL; + if (isC(testBin)) { + setG(testBin, -2, 0); + shell = catS(testBin, "Asan.sh"); + // restore original testBin + testBin[strlen(testBin)] = '.'; + if (!fileExists(shell)) { + s = replaceManyS(ASAN_SH_TEMPLATE, "testBin", testBin, "asanBin", asanBin); + writeFileG(s, shell); + free(s); + fileChmod(shell, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); + printf("Generated: "BLD GRN "%s" RST"\n", shell); } + } + printf("To run the asan test, execute: " BLD WHT "%s" RST "\n", shell); + free(shell); + } - printf("Generated: "BLD GRN "%s" RST " " UDL "< add the test cases in this file" RST "\nTo run the test, execute: " BLD WHT "spm test" RST "\n" - "To run the memcheck test, execute: " BLD WHT "%s" RST "\n" - BLD YLW "Warning" RST ": do not call " UDL "initLibsheepy" RST " in " UDL "%s" RST ", it conflicts with libcheck", testBin, shell, testBin); - free(shell); freeG(&pkgInfo); XSUCCESS } - if (sheepyParams.test or sheepyParams.memcheck) { + if (sheepyParams.test or sheepyParams.memcheck or sheepyParams.asan) { sheepyParams.compileOnly = 1; } @@ -538,6 +587,10 @@ int MAIN(int ARGC, char** ARGV) { libsheepy = "libsheepyMemcheck.a"; } + if (sheepyParams.libsheepyAsan) { + libsheepy = "libsheepyAsan.a"; + } + mainFilename = normalizePath(dum); sheepyRun: @@ -687,12 +740,15 @@ int MAIN(int ARGC, char** ARGV) { else if (sheepyParams.memcheck) { buildPath = catS(homedir, "build", actualDir, "Memcheck"); } + else if (sheepyParams.asan) { + buildPath = catS(homedir, "build", actualDir, "Asan"); + } else { // compile, run or clean buildPath = catS(homedir, "build", actualDir); if (sheepyParams.clean) { // delete test build folders: test, memcheck... - dum = catS(homedir, "build", actualDir, "Test"); + dum = catS(homedir, "build", actualDir, "Test"); if (isDir(dum)) { if (getG(cfgD, rtBool, "print_compile_commands")) { printf("rm -rf %s", dum); @@ -701,7 +757,16 @@ int MAIN(int ARGC, char** ARGV) { rmAll(dum); } free(dum); - dum = catS(homedir, "build", actualDir, "Memcheck"); + dum = catS(homedir, "build", actualDir, "Memcheck"); + if (isDir(dum)) { + if (getG(cfgD, rtBool, "print_compile_commands")) { + printf("rm -rf %s", dum); + printf("\n"); + } + rmAll(dum); + } + free(dum); + dum = catS(homedir, "build", actualDir, "Asan"); if (isDir(dum)) { if (getG(cfgD, rtBool, "print_compile_commands")) { printf("rm -rf %s", dum); @@ -1609,6 +1674,10 @@ int MAIN(int ARGC, char** ARGV) { cflagsKey = "memcheckCflags"; cflagsAlwaysKey = "memcheckCflagsAlways"; } + else if (sheepyParams.asan) { + cflagsKey = "asanCflags"; + cflagsAlwaysKey = "asanCflagsAlways"; + } else { cflagsKey = "cflags"; cflagsAlwaysKey = "cflagsAlways"; @@ -1958,6 +2027,9 @@ int MAIN(int ARGC, char** ARGV) { else if (sheepyParams.memcheck) { lflagsKey = "memcheckLflags"; } + else if (sheepyParams.asan) { + lflagsKey = "asanLflags"; + } else { lflagsKey = "lflags"; @@ -1994,6 +2066,9 @@ int MAIN(int ARGC, char** ARGV) { else if (sheepyParams.memcheck) { linkWithGoldKey = "memcheckLinkWithGold"; } + else if (sheepyParams.asan) { + linkWithGoldKey = "asanLinkWithGold"; + } else { linkWithGoldKey = "linkWithGold"; } diff --git a/src/sheepy.h b/src/sheepy.h @@ -27,13 +27,15 @@ struct { int clean; int test; int memcheck; + int libsheepyMemcheck; + int asan; + int libsheepyAsan; int new; int showExe; int removeBuild; int parallel; int cclass; int genTest; - int libsheepyMemcheck; } sheepyParams; // MacOS definition @@ -441,12 +443,12 @@ __calls\n\ " char **functions = NULL;\n"\ " char **result = NULL;\n"\ "\n"\ -" argc = ARGC; argv = ARGV;;//\n"\ +" argc = ARGC; argv = ARGV;\n"\ "\n"\ " initLibsheepy(argv[0]);\n"\ "\n"\ -" if (argc < 3) {\n"\ -" printf(\"Give a parameter: unit test c file and template file\");\n"\ +" if (argc < 4) {\n"\ +" printf(\"Give 3 parameters: unit test c file, template file and output file\");\n"\ " printf(\"\\n\");\n"\ " XFAILURE;\n"\ " }\n"\ @@ -517,8 +519,8 @@ __calls\n\ " }\n"\ "\n"\ " // save result\n"\ -" putsG(\"memcheckBin\");\n"\ -" writeText(\"memcheckBin\", result);\n"\ +" putsG(argv[3]);\n"\ +" writeText(argv[3], result);\n"\ "\n"\ " listFreeManyS(tests, functions, result, template);\n"\ "\n"\ @@ -527,5 +529,9 @@ __calls\n\ "// vim: set expandtab ts=2 sw=2:" #define MEMCHECK_SH_TEMPLATE "\ -./runMemtest.c testBin memTest.c.template\n\ +./runMemtest.c testBin memTest.c.template memcheckBin\n\ spm memcheck" + +#define ASAN_SH_TEMPLATE "\ +./runMemtest.c testBin memTest.c.template asanBin\n\ +spm asan" diff --git a/src/spm.c b/src/spm.c @@ -67,6 +67,7 @@ smallDictt *loadYML(char *path); bool installDependencies(bool isGlobal, smallDictt *cfgD, smallDictt *d, const char *name); int testPackage(smallDictt *cfgD, smallDictt *packageyml); void memcheckPackage(smallDictt *cfgD, smallDictt *packageyml); +void asanPackage(smallDictt *cfgD, smallDictt *packageyml); void listAllPackages(smallDictt *cfgD, smallArrayt *options); void showPackage(smallDictt *cfgD, smallStringt *o); void showPackageInfo(smallStringt *path); @@ -241,6 +242,14 @@ int MAIN(int ARGC, char** ARGV) { params.showmcheck += 1; bum = true; } + else if (eqG(argv[i], "asan")) { + params.asan += 1; + bum = true; + } + else if (eqG(argv[i], "showasan")) { + params.showasan += 1; + bum = true; + } else if (eqG(argv[i], "doc")) { params.doc += 1; bum = true; @@ -305,7 +314,7 @@ int MAIN(int ARGC, char** ARGV) { XFAILURE } - int paramsSum = params.install + params.publish + params.show + params.new + params.update + params.uninstall + params.find + params.top + params.hot + params.latest + params.whoami + params.profile + params.unpublish + params.info + params.adduser + params.apikey + params.test + params.memcheck + params.showmcheck + params.doc + params.add; + int paramsSum = params.install + params.publish + params.show + params.new + params.update + params.uninstall + params.find + params.top + params.hot + params.latest + params.whoami + params.profile + params.unpublish + params.info + params.adduser + params.apikey + params.test + params.memcheck + params.showmcheck + params.asan + params.showasan + params.doc + params.add; if (paramsSum > 1) { putsG(BLD RED "Conflicting commands." RST); XFAILURE @@ -842,6 +851,38 @@ int MAIN(int ARGC, char** ARGV) { terminateG(packageyml); } + if (params.asan) { + if (!fileExists(PACKAGE)) { + // command line is spm memcheck and there is no package.yml + puts(BLD RED "Package name missing!" RST); + XFAILURE + } + smallDictt *d = loadYML(PACKAGE); + asanPackage(cfgD, d); + terminateG(d); + } + + if (params.showasan) { + smallDictt *packageyml = NULL; + if (fileExists(PACKAGE)) { + packageyml = loadYML(PACKAGE); + } + const char *asanCmd = NULL; + if (packageyml and hasG(packageyml, "asanCmd")) { + asanCmd = getG(packageyml, rtChar, "asanCmd"); + } + else if (hasG(cfgD, "asanCmd")) { + asanCmd = getG(cfgD, rtChar, "asanCmd"); + } + if (asanCmd) { + printf("Current asan command: " BLD GRN "%s" RST "\n", asanCmd); + } + else { + puts(BLD RED "No asan command (asanCmd) found, searched " HOME_DIR CONFIG_NAME " and package.yml" RST); + } + terminateG(packageyml); + } + if (params.doc) { smallDictt *d = NULL; if (fileExists(PACKAGE)) { @@ -1384,7 +1425,8 @@ void memcheckPackage(smallDictt *cfgD, smallDictt *packageyml) { if (getG(cfgD, rtBool, "print_compile_commands")) { printf("%s ; %s %s\n", bin, mcheckCmd, bin); } - systemf("%s ; %s %s\n", bin, mcheckCmd, bin); + int r; + spmAssign(r, commandf("%s ; %s %s\n", bin, mcheckCmd, bin)); if (getG(cfgD, rtBool, "clean_exe")) { @@ -1393,9 +1435,78 @@ void memcheckPackage(smallDictt *cfgD, smallDictt *packageyml) { printf("\n"); } rmAll(bin); + } + + exit(r); } } + + +void asanPackage(smallDictt *cfgD, smallDictt *packageyml) { + + if (!hasG(packageyml, "asanBin")) { + putsG(BLD RED "asanBin not set in " PACKAGE RST); + } + else { + const char *asanCmd; + if (hasG(packageyml, "asanCmd")) { + asanCmd = getG(packageyml, rtChar, "asanCmd"); + } + else if (hasG(cfgD, "asanCmd")) { + asanCmd = getG(cfgD, rtChar, "asanCmd"); } + else { + // asan command not found + putsG(BLD RED "asan command not found. Searched " PACKAGE " and " HOME_DIR CONFIG_NAME RST); + return; + } + + char *bin = getNDupG(packageyml, rtChar, "asanBin"); + + if (!bin) { + putsG(BLD RED "asanBin is not set in " PACKAGE RST); + return; + } + + if (!fileExists(bin)) { + printf(BLD RED "asanBin %s not found" RST, bin); + return; + } + + // dont need to delete intermediary files because the test is compiled in a seperate folder + // (delete intermediary files) + + // compile test + if (getG(cfgD, rtBool, "print_compile_commands")) { + printf("sheepy -a %s\n", bin); + } + if (commandf("sheepy -a %s", bin)) { + XFAILURE + } + + // remove extension from asanBin + if ((getS(bin, -2) == '.') and (getS(bin, -1) == 'c')) { + setS(bin, -2, 0); + } + + if (getG(cfgD, rtBool, "print_compile_commands")) { + printf("%s %s\n", asanCmd, bin); + } + int r; + spmAssign(r, commandf("%s %s\n", asanCmd, bin)); + + + if (getG(cfgD, rtBool, "clean_exe")) { + if (getG(cfgD, rtBool, "print_compile_commands")) { + printf("rm %s", bin); + printf("\n"); + } + rmAll(bin); + } + + exit(r); +} + } void listAllPackages(smallDictt *cfgD, smallArrayt *options) { diff --git a/src/spm.h b/src/spm.h @@ -32,6 +32,8 @@ typedef struct { int test; int memcheck; int showmcheck; + int asan; + int showasan; int doc; int show; int update; @@ -57,3 +59,5 @@ typedef struct { bool pigz; } installArgst; +// bug in cg_c +#define spmAssign(r, func) r = func