diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml index 2b6f529..8d69c63 100644 --- a/.settings/language.settings.xml +++ b/.settings/language.settings.xml @@ -4,7 +4,7 @@ - + diff --git a/Makefile b/Makefile index dca67b9..e2e4d6b 100644 --- a/Makefile +++ b/Makefile @@ -28,17 +28,18 @@ else $(info WARNING! Doxygen is not available. Will skip 'dox' target) endif - # Link against thread lib LDFLAGS += -pthread +export + # Build everything... .PHONY: all -all: shared static $(DOC_TARGETS) check +all: shared static tools $(DOC_TARGETS) check # Shared libraries (versioned and unversioned) .PHONY: shared -shared: $(LIB)/libsmax.so +shared: $(LIB)/libsmax.so # Legacy static libraries (locally built) .PHONY: static @@ -46,8 +47,14 @@ static: $(LIB)/libsmax.a # Run regression tests .PHONY: test -test: - make -C test +test: SRC := tests/src +test: shared static + make -f test.mk + +.PHONY: tools +tools: SRC := tools/src +tools: shared static + make -f tools.mk # Remove intermediates .PHONY: clean @@ -59,7 +66,6 @@ clean: distclean: clean rm -f Doxyfile.local $(LIB)/libsmax.so* $(LIB)/libsmax.a - # ---------------------------------------------------------------------------- # The nitty-gritty stuff below # ---------------------------------------------------------------------------- @@ -79,6 +85,7 @@ $(LIB)/libsmax.so.$(SO_VERSION): $(SOURCES) # Static library $(LIB)/libsmax.a: $(OBJECTS) | $(LIB) Makefile + README-smax.md: README.md LINE=`sed -n '/\# /{=;q;}' $<` && tail -n +$$((LINE+2)) $< > $@ @@ -105,6 +112,7 @@ help: @echo @echo " shared Builds the shared 'libsmax.so' (linked to versioned)." @echo " static Builds the static 'lib/libsmax.a' library." + @echo " tools Command line tools: 'bin/smaxValue' and 'bin/smaxWrite'." @echo " local-dox Compiles local HTML API documentation using 'doxygen'." @echo " check Performs static analysis with 'cppcheck'." @echo " all All of the above." @@ -121,4 +129,3 @@ Makefile: config.mk build.mk include build.mk - diff --git a/README.md b/README.md index 503a1ff..d0c6ba2 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ Last Updated: 18 September 2024 - [Introduction](#introduction) - [Prerequisites](#prerequisites) - [Building the SMA-X C library](#building) + - [Command-line tools](#command-line-tools) - [Initial configuration](#configuration) - [Connecting to / disconnecting from SMA-X](#connecting) - [Sharing and pulling data](#sharing-and-pulling) @@ -111,6 +112,12 @@ prior to invoking `make`. The following build variables can be configured: automatically. - `LDFLAGS`: Linker flags (default is `-lm`). Note, `-lredisx -lxchange` will be added automatically. + + - `THREADS`: Linker flags for the __pthread__ library. It will be added to `LDFLAGS` automatically. (default: + `-pthread`) + + - `RTLIB`: Linker flags fo linking against a realtime (if necessary). It will be added to `LDFLAGS` + automatically. (default: empty) - `BUILD_MODE`: You can set it to `debug` to enable debugging features: it will initialize the global `xDebug` variable to `TRUE` and add `-g` to `CFLAGS`. @@ -124,6 +131,26 @@ desired `make` target(s). (You can use `make help` to get a summary of the avail ------------------------------------------------------------------------------ + +## Command-line tools + +The __smax-clib__ library provides two basic command-line tools: + + - `smaxValue` -- for exploring the contents of SMA-X, including associated metadata, and + - `smaxWrite` -- for putting data into SMA-X from the shell. + +The tools can be compiled with `make tools`. Both tools can be run with the `--help` option for a simple help screen on +usage. E.g.: + +```bash + $ smaxValue --help +``` + +These command-line tools provide a simple means to interact with SMA-X from the shell or a scripting language, such +as `bash`, or `perl` (also `python` though we recommend to use the native +[Smithsonian/smax-python](https://github.com/Smithsonian/smax-python) library instead). + +------------------------------------------------------------------------------ ## Initial configuration diff --git a/build.mk b/build.mk index 546e25e..c96f119 100644 --- a/build.mk +++ b/build.mk @@ -22,7 +22,11 @@ $(LIB)/lib%.so: # Static library: *.a $(LIB)/%.a: ar -rc $@ $^ - ranlib $@ + ranlib $@ + +# Simple binaries +$(BIN)/%: $(OBJ)/%.o | $(BIN) + $(CC) -o $@ $^ $(LDFLAGS) # Create sub-directories for build targets dep $(OBJ) $(LIB) $(BIN) apidoc: diff --git a/config.mk b/config.mk index 6af53e7..5b821ca 100644 --- a/config.mk +++ b/config.mk @@ -39,24 +39,30 @@ CFLAGS ?= -Os -Wall -std=c99 #CFLAGS += -Wextra # Link against math libs (for e.g. isnan()) -LDFLAGS ?= -lm +LDFLAGS ?= -lm + +# Link flags to use for threading with pthread +THREADS ?= -pthread + +# Runtime libraries to link against (if any) +#RTLIB ?= -lrt # Compile and link against a specific redisx library (if defined) ifdef REDISX CPPFLAGS += -I$(REDISX)/include LDFLAGS += -L$(REDISX)/lib - LD_LIBRARY_PATH = $(REDISX)/lib:$(LD_LIBRARY_PATH) + LD_LIBRARY_PATH := $(REDISX)/lib:$(LD_LIBRARY_PATH) endif # Compile and link against a specific xchange library (if defined) ifdef XCHANGE CPPFLAGS += -I$(XCHANGE)/include LDFLAGS += -L$(XCHANGE)/lib - LD_LIBRARY_PATH = $(XCHANGE)/lib:$(LD_LIBRARY_PATH) + LD_LIBRARY_PATH := $(XCHANGE)/lib:$(LD_LIBRARY_PATH) endif # Always link against the xchange lib. -LDFLAGS += -lredisx -lxchange +LDFLAGS += -lredisx -lxchange $(RTLIB) $(THREADS) # cppcheck options for 'check' target CHECKOPTS ?= --enable=performance,warning,portability,style --language=c \ diff --git a/test.mk b/test.mk new file mode 100644 index 0000000..f2f216d --- /dev/null +++ b/test.mk @@ -0,0 +1,21 @@ +# Load the common Makefile definitions... +include config.mk + +CFLAGS += -g +LDFLAGS += -L$(LIB) -lsmax + +LD_LIBRARY_PATH := $(LIB):$(LD_LIBRARY_PATH) + + +TESTS = $(BIN)/simpleIntTest $(BIN)/simpleIntsTest $(BIN)/structTest $(BIN)/queueTest $(BIN)/lazyTest \ + $(BIN)/waitTest $(BIN)/resilientTest + +# Top level make targets... +all: $(TESTS) + + +$(BIN)/%: $(OBJ)/%.o | $(BIN) + $(CC) -o $@ $^ $(LDFLAGS) + +# Standard generic rules and targets... +include build.mk diff --git a/tests/Makefile b/tests/Makefile deleted file mode 100644 index 05e6812..0000000 --- a/tests/Makefile +++ /dev/null @@ -1,41 +0,0 @@ -INC = ../include - -# Load the common Makefile definitions... -include $(GLOBALINC)/setup.mk - -ifeq ($(OSNAME),Linux) - LDFLAGS += -lrt -endif - -CFLAGS0 += -g - -LDFLAGS += -lm $(NETFLAGS) $(THREADS) - -TESTS = $(BIN)/simpleIntTest $(BIN)/simpleIntsTest $(BIN)/structTest $(BIN)/queueTest $(BIN)/lazyTest \ - $(BIN)/waitTest $(BIN)/resilientTest - -# Top level make targets... -all: $(TESTS) - -# Additional dependencies... -$(BIN)/benchmarkRM: $(RMDSM) - -$(BIN)/lazyTest: $(SMAX) - -$(BIN)/queueTest: $(SMAX) - -$(BIN)/simpleIntTest: $(SMAX) - -$(BIN)/simpleIntsTest: $(SMAX) - -$(BIN)/structTest: $(SMAX) - -$(BIN)/waitTest: $(SMAX) - -$(BIN)/resilientTest: $(SMAX) - - - - -# Standard generic rules and targets... -include $(GLOBALINC)/recipes.mk diff --git a/tests/src/lazyTest.c b/tests/src/lazyTest.c index dad0aeb..58f8eff 100644 --- a/tests/src/lazyTest.c +++ b/tests/src/lazyTest.c @@ -10,6 +10,7 @@ * to smaxLazyPull(), and then only when an update notification is received for the lazy value. */ +#define _POSIX_C_SOURCE 199309L ///< for nanosleep() #include #include @@ -97,11 +98,14 @@ int main(int argc, const char *argv[]) { // Give the PollingThread a bit of time to detect the change and exit normally while(--timeoutLoops >= 0) { + struct timespec interval = { 0, 10000000 }; // Check every 10ms + if(gotUpdate) { printf("lazy: OK (%d queries, %d update[s])\n", nQueries, nUpdates); exit(0); } - usleep(10000); // Check every 10ms + + nanosleep(&interval, NULL); } // Once we are done with a set of lazy pulling, we can flush all lazy caches diff --git a/tests/src/queueTest.c b/tests/src/queueTest.c index 67d8fb4..8005d1a 100644 --- a/tests/src/queueTest.c +++ b/tests/src/queueTest.c @@ -172,10 +172,11 @@ struct { // This is an example callback function that we want to be called when // out data has been queued for high-throughput pulls from SMA-X... -static void checkPull(char *arg) { +static void checkPull(void *arg) { + char *str = (char *) arg; // Check the argument that was passed to us... - if(strcmp(arg, CALLBACKARG)) { + if(strcmp(str, CALLBACKARG)) { fprintf(stderr, "ERROR! callback: Unexpected callback argument.\n"); exit(-1); } diff --git a/tests/src/waitTest.c b/tests/src/waitTest.c index 4b8b6fb..8ce7c0e 100644 --- a/tests/src/waitTest.c +++ b/tests/src/waitTest.c @@ -10,6 +10,7 @@ * to smaxLazyPull(), and then only when an update notification is received for the lazy value. */ +#define _POSIX_C_SOURCE 199309L ///< for nanosleep() #include #include @@ -93,11 +94,14 @@ int main(int argc, const char *argv[]) { // Give the WaitingThread a bit of time to detect the change and exit normally while(--timeoutLoops >= 0) { + struct timespec interval = { 0, 10000000 }; // Check every 10ms + if(gotUpdate) { printf("wait: OK\n"); exit(0); } - usleep(10000); // Check every 10ms + + nanosleep(&interval, NULL); // Check every 10ms } // If we go this far, then the polling thread did not get the update diff --git a/tools.mk b/tools.mk new file mode 100644 index 0000000..2b70a14 --- /dev/null +++ b/tools.mk @@ -0,0 +1,15 @@ +# Load the common Makefile definitions... +include config.mk + +LDFLAGS += -L$(LIB) -lsmax +LD_LIBRARY_PATH := $(LIB):$(LD_LIBRARY_PATH) + +# Top level make targets... +all: $(BIN)/smaxValue $(BIN)/smaxWrite + +# Standard generic rules and targets... +include build.mk + + + + diff --git a/tools/Makefile b/tools/Makefile deleted file mode 100644 index 8dd0590..0000000 --- a/tools/Makefile +++ /dev/null @@ -1,29 +0,0 @@ -# Load the common Makefile definitions... -include $(GLOBALINC)/setup.mk - -ifeq ($(OSNAME),Linux) - LDFLAGS += -lrt -else - LDFLAGS += -llynx -endif - -LDFLAGS += $(NETFLAGS) $(THREADS) - -# Top level make targets... -all: $(BIN)/smaxValue $(BIN)/smaxWrite - -# Additional dependencies... -$(BIN)/smaxValue: $(OBJ)/smaxValue.o $(SMAX) - -$(BIN)/smaxWrite: $(OBJ)/smaxWrite.o $(SMAX) - -install: install-platform - -install-platform: $(BIN)/smaxValue $(BIN)/smaxWrite - -# Standard generic rules and targets... -include $(GLOBALINC)/recipes.mk - - - - diff --git a/tools/src/smaxValue.c b/tools/src/smaxValue.c index 9c0365c..fef075d 100644 --- a/tools/src/smaxValue.c +++ b/tools/src/smaxValue.c @@ -110,7 +110,7 @@ static int printValue(const char *group, const char *key) { strftime(date, 100, "%Y-%m-%d %H:%M:%S", ts); printf("\n"); - printf(MAG " #" BLU " Type: " RST "%s\n", xStringType(meta.storeType)); + printf(MAG " #" BLU " Type: " RST "%s\n", smaxStringType(meta.storeType)); printf(MAG " #" BLU " Size: " RST "%s\n", dims); printf(MAG " #" BLU " Origin: " RST "%s\n", meta.origin[0] ? meta.origin : RED "" RST); printf(MAG " #" BLU " Time: " RST "%s (" GRN "%s.%03ld" CYN " UTC" RST ")\n", TS, date, (meta.timestamp.tv_nsec / 1000000)); @@ -217,7 +217,7 @@ static void setOption(char *argv[], int *next) { if(!strcmp(option, "m") || !strcmp(option, "-meta")) showMeta = TRUE; else if(!strcmp(option, "e") || !strcmp(option, "-errors")) printErrors = TRUE; else if(!strcmp(option, "l") || !strcmp(option, "-list")) showList = TRUE; - else if(!strcmp(option, "t") || !strcmp(option, "-type")) type = xTypeForString(argv[(*next)++]); + else if(!strcmp(option, "t") || !strcmp(option, "-type")) type = smaxTypeForString(argv[(*next)++]); else if(!strcmp(option, "n") || !strcmp(option, "-count")) count = atoi(argv[(*next)++]); else if(!strcmp(option, "s") || !strcmp(option, "-server")) host = argv[(*next)++]; else fprintf(stderr, "WARNING! no option: -%s\n", option); diff --git a/tools/src/smaxWrite.c b/tools/src/smaxWrite.c index fae32c0..f53bc81 100644 --- a/tools/src/smaxWrite.c +++ b/tools/src/smaxWrite.c @@ -45,7 +45,7 @@ static void setOption(char *argv[], int *next) { if(!strcmp(option, "t") || !strcmp(option, "-type")) { sType = argv[(*next)++]; - f.type = xTypeForString(sType); + f.type = smaxTypeForString(sType); if(f.type == X_UNKNOWN || f.type == X_STRUCT) { fprintf(stderr, "ERROR! Invalid type: %s\n", sType); exit(1);