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:
| M | src/common.c | | | 6 | ++++-- |
| M | src/common.h | | | 37 | +++++++++++++++++++++++++++++++------ |
| M | src/sheepy.c | | | 129 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------- |
| M | src/sheepy.h | | | 20 | +++++++++++++------- |
| M | src/spm.c | | | 115 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- |
| M | src/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