[LITMUS^RT] [PATCH] Implement modules rule and move skeleton tasks to examples/
Manohar Vanga
mvanga at mpi-sws.org
Thu Feb 6 00:29:14 CET 2014
This patch adds a modules rule to the Makefile in liblitmus that
allows the compilation of out-of-tree tasks with a simple Makefile
that is syntactically very clean (similar to kernel module
Makefile's).
This patch also moves base_task and base_mt_task to a separate
examples/ directory that employs the new module rule.
Further details regarding how to use the modules rule can be found
in examples/README.
Signed-off-by: Manohar Vanga <mvanga at mpi-sws.org>
---
Makefile | 15 ++--
bin/base_mt_task.c | 201 -----------------------------------------------
bin/base_task.c | 162 --------------------------------------
examples/Makefile | 11 +++
examples/README | 37 +++++++++
examples/base_mt_task.c | 201 +++++++++++++++++++++++++++++++++++++++++++++++
examples/base_task.c | 162 ++++++++++++++++++++++++++++++++++++++
inc/module.makefile | 10 +++
8 files changed, 429 insertions(+), 370 deletions(-)
delete mode 100644 bin/base_mt_task.c
delete mode 100644 bin/base_task.c
create mode 100644 examples/Makefile
create mode 100644 examples/README
create mode 100644 examples/base_mt_task.c
create mode 100644 examples/base_task.c
create mode 100644 inc/module.makefile
diff --git a/Makefile b/Makefile
index e8003e8..ea10fee 100644
--- a/Makefile
+++ b/Makefile
@@ -72,8 +72,8 @@ AR := ${CROSS_COMPILE}${AR}
# Targets
all = lib ${rt-apps}
-rt-apps = cycles base_task rt_launch rtspin release_ts measure_syscall \
- base_mt_task uncache runtests
+rt-apps = cycles rt_launch rtspin release_ts measure_syscall \
+ uncache runtests
.PHONY: all lib clean dump-config TAGS tags cscope help
@@ -113,6 +113,8 @@ dump-config:
AR "${AR}" \
obj-all "${obj-all}"
+modules: liblitmus.a $(obj-m)
+
help:
@cat INSTALL
@@ -212,11 +214,6 @@ vpath %.c bin/
obj-cycles = cycles.o
-obj-base_task = base_task.o
-
-obj-base_mt_task = base_mt_task.o
-ldf-base_mt_task = -pthread
-
obj-rt_launch = rt_launch.o common.o
obj-rtspin = rtspin.o common.o
@@ -234,6 +231,10 @@ lib-measure_syscall = -lm
# Build everything that depends on liblitmus.
.SECONDEXPANSION:
+$(obj-m): $$M/$$(obj-$$@)
+ $(CC) -o $M/$@ $(LDFLAGS) ${ldf-$@} $M/$(obj-$@) $(LOADLIBS) $(LDLIBS) ${liblitmus-flags} ${lib-$@}
+
+.SECONDEXPANSION:
${rt-apps}: $${obj-$$@} liblitmus.a
$(CC) -o $@ $(LDFLAGS) ${ldf-$@} $(filter-out liblitmus.a,$+) $(LOADLIBS) $(LDLIBS) ${liblitmus-flags} ${lib-$@}
diff --git a/bin/base_mt_task.c b/bin/base_mt_task.c
deleted file mode 100644
index aec79a4..0000000
--- a/bin/base_mt_task.c
+++ /dev/null
@@ -1,201 +0,0 @@
-/* based_mt_task.c -- A basic multi-threaded real-time task skeleton.
- *
- * This (by itself useless) task demos how to setup a multi-threaded LITMUS^RT
- * real-time task. Familiarity with the single threaded example (base_task.c)
- * is assumed.
- *
- * Currently, liblitmus still lacks automated support for real-time
- * tasks, but internaly it is thread-safe, and thus can be used together
- * with pthreads.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-/* Include gettid() */
-#include <sys/types.h>
-
-/* Include threading support. */
-#include <pthread.h>
-
-/* Include the LITMUS^RT API.*/
-#include "litmus.h"
-
-#define PERIOD 100
-#define RELATIVE_DEADLINE 100
-#define EXEC_COST 10
-
-/* Let's create 10 threads in the example,
- * for a total utilization of 1.
- */
-#define NUM_THREADS 10
-
-/* The information passed to each thread. Could be anything. */
-struct thread_context {
- int id;
-};
-
-/* The real-time thread program. Doesn't have to be the same for
- * all threads. Here, we only have one that will invoke job().
- */
-void* rt_thread(void *tcontext);
-
-/* Declare the periodically invoked job.
- * Returns 1 -> task should exit.
- * 0 -> task should continue.
- */
-int job(void);
-
-
-/* Catch errors.
- */
-#define CALL( exp ) do { \
- int ret; \
- ret = exp; \
- if (ret != 0) \
- fprintf(stderr, "%s failed: %m\n", #exp);\
- else \
- fprintf(stderr, "%s ok.\n", #exp); \
- } while (0)
-
-
-/* Basic setup is the same as in the single-threaded example. However,
- * we do some thread initiliazation first before invoking the job.
- */
-int main(int argc, char** argv)
-{
- int i;
- struct thread_context ctx[NUM_THREADS];
- pthread_t task[NUM_THREADS];
-
- /* The task is in background mode upon startup. */
-
-
- /*****
- * 1) Command line paramter parsing would be done here.
- */
-
-
-
- /*****
- * 2) Work environment (e.g., global data structures, file data, etc.) would
- * be setup here.
- */
-
-
-
- /*****
- * 3) Initialize LITMUS^RT.
- * Task parameters will be specified per thread.
- */
- init_litmus();
-
-
- /*****
- * 4) Launch threads.
- */
- for (i = 0; i < NUM_THREADS; i++) {
- ctx[i].id = i;
- pthread_create(task + i, NULL, rt_thread, (void *) (ctx + i));
- }
-
-
- /*****
- * 5) Wait for RT threads to terminate.
- */
- for (i = 0; i < NUM_THREADS; i++)
- pthread_join(task[i], NULL);
-
-
- /*****
- * 6) Clean up, maybe print results and stats, and exit.
- */
- return 0;
-}
-
-
-
-/* A real-time thread is very similar to the main function of a single-threaded
- * real-time app. Notice, that init_rt_thread() is called to initialized per-thread
- * data structures of the LITMUS^RT user space libary.
- */
-void* rt_thread(void *tcontext)
-{
- int do_exit;
- struct thread_context *ctx = (struct thread_context *) tcontext;
- struct rt_task param;
-
- /* Set up task parameters */
- init_rt_task_param(¶m);
- param.exec_cost = ms2ns(EXEC_COST);
- param.period = ms2ns(PERIOD);
- param.relative_deadline = ms2ns(RELATIVE_DEADLINE);
-
- /* What to do in the case of budget overruns? */
- param.budget_policy = NO_ENFORCEMENT;
-
- /* The task class parameter is ignored by most plugins. */
- param.cls = RT_CLASS_SOFT;
-
- /* The priority parameter is only used by fixed-priority plugins. */
- param.priority = LITMUS_LOWEST_PRIORITY;
-
- /* Make presence visible. */
- printf("RT Thread %d active.\n", ctx->id);
-
- /*****
- * 1) Initialize real-time settings.
- */
- CALL( init_rt_thread() );
-
- /* To specify a partition, do
- *
- * param.cpu = CPU;
- * be_migrate_to(CPU);
- *
- * where CPU ranges from 0 to "Number of CPUs" - 1 before calling
- * set_rt_task_param().
- */
- CALL( set_rt_task_param(gettid(), ¶m) );
-
- /*****
- * 2) Transition to real-time mode.
- */
- CALL( task_mode(LITMUS_RT_TASK) );
-
- /* The task is now executing as a real-time task if the call didn't fail.
- */
-
-
-
- /*****
- * 3) Invoke real-time jobs.
- */
- do {
- /* Wait until the next job is released. */
- sleep_next_period();
- /* Invoke job. */
- do_exit = job();
- } while (!do_exit);
-
-
-
- /*****
- * 4) Transition to background mode.
- */
- CALL( task_mode(BACKGROUND_TASK) );
-
-
- return NULL;
-}
-
-
-
-int job(void)
-{
- /* Do real-time calculation. */
-
- /* Don't exit. */
- return 0;
-}
diff --git a/bin/base_task.c b/bin/base_task.c
deleted file mode 100644
index 09edba9..0000000
--- a/bin/base_task.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/* based_task.c -- A basic real-time task skeleton.
- *
- * This (by itself useless) task demos how to setup a
- * single-threaded LITMUS^RT real-time task.
- */
-
-/* First, we include standard headers.
- * Generally speaking, a LITMUS^RT real-time task can perform any
- * system call, etc., but no real-time guarantees can be made if a
- * system call blocks. To be on the safe side, only use I/O for debugging
- * purposes and from non-real-time sections.
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-/* Second, we include the LITMUS^RT user space library header.
- * This header, part of liblitmus, provides the user space API of
- * LITMUS^RT.
- */
-#include "litmus.h"
-
-/* Next, we define period and execution cost to be constant.
- * These are only constants for convenience in this example, they can be
- * determined at run time, e.g., from command line parameters.
- *
- * These are in milliseconds.
- */
-#define PERIOD 100
-#define RELATIVE_DEADLINE 100
-#define EXEC_COST 10
-
-/* Catch errors.
- */
-#define CALL( exp ) do { \
- int ret; \
- ret = exp; \
- if (ret != 0) \
- fprintf(stderr, "%s failed: %m\n", #exp);\
- else \
- fprintf(stderr, "%s ok.\n", #exp); \
- } while (0)
-
-
-/* Declare the periodically invoked job.
- * Returns 1 -> task should exit.
- * 0 -> task should continue.
- */
-int job(void);
-
-/* typically, main() does a couple of things:
- * 1) parse command line parameters, etc.
- * 2) Setup work environment.
- * 3) Setup real-time parameters.
- * 4) Transition to real-time mode.
- * 5) Invoke periodic or sporadic jobs.
- * 6) Transition to background mode.
- * 7) Clean up and exit.
- *
- * The following main() function provides the basic skeleton of a single-threaded
- * LITMUS^RT real-time task. In a real program, all the return values should be
- * checked for errors.
- */
-int main(int argc, char** argv)
-{
- int do_exit;
- struct rt_task param;
-
- /* Setup task parameters */
- init_rt_task_param(¶m);
- param.exec_cost = ms2ns(EXEC_COST);
- param.period = ms2ns(PERIOD);
- param.relative_deadline = ms2ns(RELATIVE_DEADLINE);
-
- /* What to do in the case of budget overruns? */
- param.budget_policy = NO_ENFORCEMENT;
-
- /* The task class parameter is ignored by most plugins. */
- param.cls = RT_CLASS_SOFT;
-
- /* The priority parameter is only used by fixed-priority plugins. */
- param.priority = LITMUS_LOWEST_PRIORITY;
-
- /* The task is in background mode upon startup. */
-
-
- /*****
- * 1) Command line paramter parsing would be done here.
- */
-
-
-
- /*****
- * 2) Work environment (e.g., global data structures, file data, etc.) would
- * be setup here.
- */
-
-
-
- /*****
- * 3) Setup real-time parameters.
- * In this example, we create a sporadic task that does not specify a
- * target partition (and thus is intended to run under global scheduling).
- * If this were to execute under a partitioned scheduler, it would be assigned
- * to the first partition (since partitioning is performed offline).
- */
- CALL( init_litmus() );
-
- /* To specify a partition, do
- *
- * param.cpu = CPU;
- * be_migrate_to(CPU);
- *
- * where CPU ranges from 0 to "Number of CPUs" - 1 before calling
- * set_rt_task_param().
- */
- CALL( set_rt_task_param(gettid(), ¶m) );
-
-
- /*****
- * 4) Transition to real-time mode.
- */
- CALL( task_mode(LITMUS_RT_TASK) );
-
- /* The task is now executing as a real-time task if the call didn't fail.
- */
-
-
-
- /*****
- * 5) Invoke real-time jobs.
- */
- do {
- /* Wait until the next job is released. */
- sleep_next_period();
- /* Invoke job. */
- do_exit = job();
- } while (!do_exit);
-
-
-
- /*****
- * 6) Transition to background mode.
- */
- CALL( task_mode(BACKGROUND_TASK) );
-
-
-
- /*****
- * 7) Clean up, maybe print results and stats, and exit.
- */
- return 0;
-}
-
-
-int job(void)
-{
- /* Do real-time calculation. */
-
- /* Don't exit. */
- return 0;
-}
diff --git a/examples/Makefile b/examples/Makefile
new file mode 100644
index 0000000..2583c59
--- /dev/null
+++ b/examples/Makefile
@@ -0,0 +1,11 @@
+# Define the list of targets we want
+obj-m += base_task base_mt_task
+
+# Define the object files for each target that we want
+obj-base_task += base_task.o
+obj-base_mt_task += base_mt_task.o
+
+# If a specific target needs a library, use lib-NAME
+lib-base_mt_task = -lpthread
+
+include $(LIBLITMUS)/inc/module.makefile
diff --git a/examples/README b/examples/README
new file mode 100644
index 0000000..cee4f78
--- /dev/null
+++ b/examples/README
@@ -0,0 +1,37 @@
+================================================================================
+Compiling liblitmus Tasks
+================================================================================
+
+This file describes how to compile LITMUS^RT tasks using the modules
+rule of the Makefile.
+
+Before beginning, please ensure that the LIBLITMUS environment variable
+is set to the location of the liblitmus source tree on disk. You can
+do this with the following (can be placed in your .bashrc):
+
+ export LIBLITMUS=/path/to/liblitmus/source
+
+Now, in your source directory, first create a Makefile that defines an
+'obj-m' variable specifying a list of your targets. For example,
+
+ obj-m = base_task base_mt_task
+
+Now, for each of the targets, define a variable specifying the list of
+object files that comprise it. The variable should be named using the
+convention 'obj-TARGET_NAME'. For example:
+
+ obj-base_task = base_task.o
+ obj-base_mt_task = base_mt_task.o
+
+If certain targets require additional libraries to be linked, they can
+be specified using the 'lib-TARGET_NAME' variable as shown below:
+
+ lib-base_mt_task = -lpthread
+
+Finally, in order to load all the rules (currently the default rule 'all' and
+the rule 'clean'), append the following line to the end of your Makefile:
+
+ include $(LIBLITMUS)/inc/module.makefile
+
+You're done! Now run 'make'! If liblitmus is not compiled, it will compile
+itself before compiling your targets.
diff --git a/examples/base_mt_task.c b/examples/base_mt_task.c
new file mode 100644
index 0000000..aec79a4
--- /dev/null
+++ b/examples/base_mt_task.c
@@ -0,0 +1,201 @@
+/* based_mt_task.c -- A basic multi-threaded real-time task skeleton.
+ *
+ * This (by itself useless) task demos how to setup a multi-threaded LITMUS^RT
+ * real-time task. Familiarity with the single threaded example (base_task.c)
+ * is assumed.
+ *
+ * Currently, liblitmus still lacks automated support for real-time
+ * tasks, but internaly it is thread-safe, and thus can be used together
+ * with pthreads.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Include gettid() */
+#include <sys/types.h>
+
+/* Include threading support. */
+#include <pthread.h>
+
+/* Include the LITMUS^RT API.*/
+#include "litmus.h"
+
+#define PERIOD 100
+#define RELATIVE_DEADLINE 100
+#define EXEC_COST 10
+
+/* Let's create 10 threads in the example,
+ * for a total utilization of 1.
+ */
+#define NUM_THREADS 10
+
+/* The information passed to each thread. Could be anything. */
+struct thread_context {
+ int id;
+};
+
+/* The real-time thread program. Doesn't have to be the same for
+ * all threads. Here, we only have one that will invoke job().
+ */
+void* rt_thread(void *tcontext);
+
+/* Declare the periodically invoked job.
+ * Returns 1 -> task should exit.
+ * 0 -> task should continue.
+ */
+int job(void);
+
+
+/* Catch errors.
+ */
+#define CALL( exp ) do { \
+ int ret; \
+ ret = exp; \
+ if (ret != 0) \
+ fprintf(stderr, "%s failed: %m\n", #exp);\
+ else \
+ fprintf(stderr, "%s ok.\n", #exp); \
+ } while (0)
+
+
+/* Basic setup is the same as in the single-threaded example. However,
+ * we do some thread initiliazation first before invoking the job.
+ */
+int main(int argc, char** argv)
+{
+ int i;
+ struct thread_context ctx[NUM_THREADS];
+ pthread_t task[NUM_THREADS];
+
+ /* The task is in background mode upon startup. */
+
+
+ /*****
+ * 1) Command line paramter parsing would be done here.
+ */
+
+
+
+ /*****
+ * 2) Work environment (e.g., global data structures, file data, etc.) would
+ * be setup here.
+ */
+
+
+
+ /*****
+ * 3) Initialize LITMUS^RT.
+ * Task parameters will be specified per thread.
+ */
+ init_litmus();
+
+
+ /*****
+ * 4) Launch threads.
+ */
+ for (i = 0; i < NUM_THREADS; i++) {
+ ctx[i].id = i;
+ pthread_create(task + i, NULL, rt_thread, (void *) (ctx + i));
+ }
+
+
+ /*****
+ * 5) Wait for RT threads to terminate.
+ */
+ for (i = 0; i < NUM_THREADS; i++)
+ pthread_join(task[i], NULL);
+
+
+ /*****
+ * 6) Clean up, maybe print results and stats, and exit.
+ */
+ return 0;
+}
+
+
+
+/* A real-time thread is very similar to the main function of a single-threaded
+ * real-time app. Notice, that init_rt_thread() is called to initialized per-thread
+ * data structures of the LITMUS^RT user space libary.
+ */
+void* rt_thread(void *tcontext)
+{
+ int do_exit;
+ struct thread_context *ctx = (struct thread_context *) tcontext;
+ struct rt_task param;
+
+ /* Set up task parameters */
+ init_rt_task_param(¶m);
+ param.exec_cost = ms2ns(EXEC_COST);
+ param.period = ms2ns(PERIOD);
+ param.relative_deadline = ms2ns(RELATIVE_DEADLINE);
+
+ /* What to do in the case of budget overruns? */
+ param.budget_policy = NO_ENFORCEMENT;
+
+ /* The task class parameter is ignored by most plugins. */
+ param.cls = RT_CLASS_SOFT;
+
+ /* The priority parameter is only used by fixed-priority plugins. */
+ param.priority = LITMUS_LOWEST_PRIORITY;
+
+ /* Make presence visible. */
+ printf("RT Thread %d active.\n", ctx->id);
+
+ /*****
+ * 1) Initialize real-time settings.
+ */
+ CALL( init_rt_thread() );
+
+ /* To specify a partition, do
+ *
+ * param.cpu = CPU;
+ * be_migrate_to(CPU);
+ *
+ * where CPU ranges from 0 to "Number of CPUs" - 1 before calling
+ * set_rt_task_param().
+ */
+ CALL( set_rt_task_param(gettid(), ¶m) );
+
+ /*****
+ * 2) Transition to real-time mode.
+ */
+ CALL( task_mode(LITMUS_RT_TASK) );
+
+ /* The task is now executing as a real-time task if the call didn't fail.
+ */
+
+
+
+ /*****
+ * 3) Invoke real-time jobs.
+ */
+ do {
+ /* Wait until the next job is released. */
+ sleep_next_period();
+ /* Invoke job. */
+ do_exit = job();
+ } while (!do_exit);
+
+
+
+ /*****
+ * 4) Transition to background mode.
+ */
+ CALL( task_mode(BACKGROUND_TASK) );
+
+
+ return NULL;
+}
+
+
+
+int job(void)
+{
+ /* Do real-time calculation. */
+
+ /* Don't exit. */
+ return 0;
+}
diff --git a/examples/base_task.c b/examples/base_task.c
new file mode 100644
index 0000000..09edba9
--- /dev/null
+++ b/examples/base_task.c
@@ -0,0 +1,162 @@
+/* based_task.c -- A basic real-time task skeleton.
+ *
+ * This (by itself useless) task demos how to setup a
+ * single-threaded LITMUS^RT real-time task.
+ */
+
+/* First, we include standard headers.
+ * Generally speaking, a LITMUS^RT real-time task can perform any
+ * system call, etc., but no real-time guarantees can be made if a
+ * system call blocks. To be on the safe side, only use I/O for debugging
+ * purposes and from non-real-time sections.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Second, we include the LITMUS^RT user space library header.
+ * This header, part of liblitmus, provides the user space API of
+ * LITMUS^RT.
+ */
+#include "litmus.h"
+
+/* Next, we define period and execution cost to be constant.
+ * These are only constants for convenience in this example, they can be
+ * determined at run time, e.g., from command line parameters.
+ *
+ * These are in milliseconds.
+ */
+#define PERIOD 100
+#define RELATIVE_DEADLINE 100
+#define EXEC_COST 10
+
+/* Catch errors.
+ */
+#define CALL( exp ) do { \
+ int ret; \
+ ret = exp; \
+ if (ret != 0) \
+ fprintf(stderr, "%s failed: %m\n", #exp);\
+ else \
+ fprintf(stderr, "%s ok.\n", #exp); \
+ } while (0)
+
+
+/* Declare the periodically invoked job.
+ * Returns 1 -> task should exit.
+ * 0 -> task should continue.
+ */
+int job(void);
+
+/* typically, main() does a couple of things:
+ * 1) parse command line parameters, etc.
+ * 2) Setup work environment.
+ * 3) Setup real-time parameters.
+ * 4) Transition to real-time mode.
+ * 5) Invoke periodic or sporadic jobs.
+ * 6) Transition to background mode.
+ * 7) Clean up and exit.
+ *
+ * The following main() function provides the basic skeleton of a single-threaded
+ * LITMUS^RT real-time task. In a real program, all the return values should be
+ * checked for errors.
+ */
+int main(int argc, char** argv)
+{
+ int do_exit;
+ struct rt_task param;
+
+ /* Setup task parameters */
+ init_rt_task_param(¶m);
+ param.exec_cost = ms2ns(EXEC_COST);
+ param.period = ms2ns(PERIOD);
+ param.relative_deadline = ms2ns(RELATIVE_DEADLINE);
+
+ /* What to do in the case of budget overruns? */
+ param.budget_policy = NO_ENFORCEMENT;
+
+ /* The task class parameter is ignored by most plugins. */
+ param.cls = RT_CLASS_SOFT;
+
+ /* The priority parameter is only used by fixed-priority plugins. */
+ param.priority = LITMUS_LOWEST_PRIORITY;
+
+ /* The task is in background mode upon startup. */
+
+
+ /*****
+ * 1) Command line paramter parsing would be done here.
+ */
+
+
+
+ /*****
+ * 2) Work environment (e.g., global data structures, file data, etc.) would
+ * be setup here.
+ */
+
+
+
+ /*****
+ * 3) Setup real-time parameters.
+ * In this example, we create a sporadic task that does not specify a
+ * target partition (and thus is intended to run under global scheduling).
+ * If this were to execute under a partitioned scheduler, it would be assigned
+ * to the first partition (since partitioning is performed offline).
+ */
+ CALL( init_litmus() );
+
+ /* To specify a partition, do
+ *
+ * param.cpu = CPU;
+ * be_migrate_to(CPU);
+ *
+ * where CPU ranges from 0 to "Number of CPUs" - 1 before calling
+ * set_rt_task_param().
+ */
+ CALL( set_rt_task_param(gettid(), ¶m) );
+
+
+ /*****
+ * 4) Transition to real-time mode.
+ */
+ CALL( task_mode(LITMUS_RT_TASK) );
+
+ /* The task is now executing as a real-time task if the call didn't fail.
+ */
+
+
+
+ /*****
+ * 5) Invoke real-time jobs.
+ */
+ do {
+ /* Wait until the next job is released. */
+ sleep_next_period();
+ /* Invoke job. */
+ do_exit = job();
+ } while (!do_exit);
+
+
+
+ /*****
+ * 6) Transition to background mode.
+ */
+ CALL( task_mode(BACKGROUND_TASK) );
+
+
+
+ /*****
+ * 7) Clean up, maybe print results and stats, and exit.
+ */
+ return 0;
+}
+
+
+int job(void)
+{
+ /* Do real-time calculation. */
+
+ /* Don't exit. */
+ return 0;
+}
diff --git a/inc/module.makefile b/inc/module.makefile
new file mode 100644
index 0000000..696155d
--- /dev/null
+++ b/inc/module.makefile
@@ -0,0 +1,10 @@
+export $(filter obj%, $(.VARIABLES))
+export $(filter lib%, $(.VARIABLES))
+
+LIBLITMUS ?= ../liblitmus
+
+all:
+ make -C $(LIBLITMUS) M=$(PWD) modules
+
+clean:
+ rm -f $(obj-m) $(foreach obj, $(obj-m), $(obj-$(obj)))
--
1.7.9.5
More information about the litmus-dev
mailing list