GNU-make 4. Running an example for "Loading Dynamic Objects" - c

The latest version of GNU-Make http://www.gnu.org/software/make/
provides many advanced capabilities, including many useful functions.
(...) On systems which support dynamically loadable objects, you can
write your own extension in any language (which can be compiled into
such an object) and load it to provide extended capabilities... http://www.gnu.org/software/make/manual/make.html#Loading-Objects
I tried to run the simple example below (a $(hello string) function). It works if I first compile the hello.so. But it doesn't work if I run it as the example provided here (with a load directive) http://www.gnu.org/software/make/manual/make.html#Loading-Objects . Make4 is installed in the current directory.
./Makefile:
all:
echo $(hello world)
load hello.so
hello.so: hello.c
$(CC) -shared -I./include -fPIC -o $# $<
./hello.c:
#include <stdlib.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <gnumake.h>
int plugin_is_GPL_compatible;
char * hello(const char *nm, unsigned int argc, char **argv)
{
int len = strlen (argv[0]) + 7;
char *buf = gmk_alloc (len);
sprintf(buf,"Hello %s",argv[0]);
return buf;
}
int hello_gmk_setup ()
{
gmk_add_function("hello", hello, 1, 1, 1);
return 1;
}
running the example:
./bin/make -v
GNU Make 4.0
Built for i686-pc-linux-gnu
$ ./bin/make
Makefile:4: hello.so: cannot open shared object file: No such file or directory
Makefile:4: *** hello.so: failed to load. Stop.
How can I run this example with the 'load' directive ?

I suggest in a comment to use
-load hello.so
instead of just load hello.so; this is analog to using -include in a Makefile.
The logic is that make plugins are generally expected to exit before you run some make using them (often, you would use a recursive make, e.g. run $(MAKE) -C subdir in a toplevel Makefile and ensure that the plugin does exist when your run $(MAKE) -C subdir)
If hello.so does not exist when -load hello.so is parsed, the GNU make would ignore that directive. (I am not sure you want that for a real plugin).
I still think that make plugins should generally not be built by the Makefile which is load-ing them.
I also believe that using Guile extensions in make is wiser than using plugins.

Related

Shared library and rpath

I cannot make rpath work properly and make my binary to search for the library in the specified folder:
I have 3 very simple files:
main.c
#include <stdio.h>
#include <func.h>
int main() {
testing();
return 1;
}
func.h
void testing();
func.c
#include "func.h"
void testing(){
printf(testing\n");
}
Then I proceed to create a shared library as it follows:
gcc -c -fpic func.c -o ../release/func.o
gcc -shared -o ../release/lib/lib_func.so ../release/func.o
And then compile the program:
gcc main.c ../release/lib/lib_time_mgmt.so -Wl,-rpath=/home/root/ -o ../release/main
I receive the next warning:
main.c:7:2: warning: implicit declaration of function ‘testing’ [-Wimplicit-function-declaration]
testing();
But besides it, the program works fine.
However, my problem is that if now I want to move the library to /home/root (as specified in rpath) it does not work and the library is still searched only in the path specified when I compiled the main.c file which is ../release/lib/lib_time_mgmt.so
What am I doing wrong?
EDIT: After accepting the answer, I leave here the exact line as I used it and made it work for whoever might find it useful:
gcc main.c -L/home/root -Wl,-rpath,'/home/root/' -l:libtime_mgmt -o ${OUT_FILE}
Note: the rpath was used with the path betwen simple '. Not sure if that was the reason why it was not working before, but it worked this way now.
rpath is not used at compile time, but rather at link/runtime... thus you probably need to use both of these:
-L /home/root - to link correctly at build time
-Wl,-rpath=/home/root - to link correctly at run-time
You should use the -l ${lib} flag to link with libraries, don't specify their path as an input.
In addition to this, convention states that the libraries are named libNAME.so - e.g:
-l func will try to link with libfunc.so
-l time_mgmt will try to link with libtime_mgmt.so
Once you've addressed the above points, try the following:
gcc main.c -L/home/root -Wl,-rpath=/home/root -lfunc -ltime_mgmt -o ${OUT_FILE}
As a final point, I'd advise that you try not to use rpath, and instead focus on installing libraries in the correct places.
Unrelated to your question, but worth noting. Your use of #include <...> vs #include "..." is questionable. See: What is the difference between #include <filename> and #include "filename"?

How to integrate CMock unit test framework with Make

Is there a way around having to switch my project to use rake as its build system? I have a large project using Make as its build system and would like to add CMock functionality for unit testing (I'm already successfully using Unity), but have found no information about integrating CMock with Makefiles (instead, it seems the world has just accepted using Ruby's rake as their build system if they want CMock to work with their projects).
I have been able to run the CMock example tests, which include a (seemingly unfinished?) 'make' example.
I've modified the test code in the 'make_example' to the following:
#include "mock_foo.h"
#include "unity.h"
void setUp(void) {}
void tearDown(void) {}
void test_main_should_initialize_foo(void) {
foo_init_Ignore();
TEST_IGNORE_MESSAGE("TODO: Implement main!");
}
however, when running 'make' from the folder with the Makefile, it seems UNITY_LINE_TYPE is undefined (e.g. something is missing from my dependency chain):
make
mkdir -p ./build
mkdir -p ./build/obj
ruby ../../scripts/create_makefile.rb --silent
cc -o build/test/obj/test_main.o -c test/test_main.c -DTEST -I ./src -I /home/user/Documents/gitrepos/cmock/vendor/unity/src -I /home/user/Documents/gitrepos/cmock/src -I ./build/test/mocks
In file included from test/test_main.c:1:0:
./build/test/mocks/mock_foo.h:27:27: error: unknown type name ‘UNITY_LINE_TYPE’
void foo_init_CMockExpect(UNITY_LINE_TYPE cmock_line);
^
build/test/MakefileTestSupport:29: recipe for target 'build/test/obj/test_main.o' failed
make: *** [build/test/obj/test_main.o] Error 1
Has anyone successfully implemented a project using Makefiles and CMock?
Turns out I was the victim of some of my own vim/clang-format configuration here.
The make_example (though not very useful out of the box) does compile and run tests properly using CMock's mocking framework if the 'unity.h' import is placed before the 'mock_xxx.h' in your test implementation (which I'm sure is called out in the documentation somewhere).
The following is an example of a working test (slightly modified test_main.c from cmock/examples/make_example):
#include "unity.h"
#include "mock_foo.h"
void setUp(void)
{
}
void tearDown(void)
{
}
void test_main_should_initialize_foo(void)
{
foo_init_Expect();
foo_init();
}
However, since my vim/clang format was set to 'SortIncludes: true', my includes were reordered to produce:
#include "mock_foo.h" // <---- the mocks must be included *after* unity.h
#include "unity.h"
void setUp(void)
{
}
void tearDown(void)
{
}
void test_main_should_initialize_foo(void)
{
foo_init_Expect();
foo_init();
}
just as I was :wq in vim.
This, of course, causes CMock problems, as it needs the unity.h definitions figured out before it tries to generate the mock_foo.h, so I was getting the error I posted above:
...
In file included from test/test_main.c:1:0:
./build/test/mocks/mock_foo.h:27:27: error: unknown type name ‘UNITY_LINE_TYPE’
void foo_init_CMockExpect(UNITY_LINE_TYPE cmock_line);
...
My Makefile (untouched from the CMock example), for posterity:
CC ?= gcc
BUILD_DIR ?= ./build
SRC_DIR ?= ./src
TEST_DIR ?= ./test
TEST_BUILD_DIR ?= ${BUILD_DIR}/test
TEST_MAKEFILE = ${TEST_BUILD_DIR}/MakefileTestSupport
OBJ ?= ${BUILD_DIR}/obj
OBJ_DIR = ${OBJ}
default: all
all: setup test ${BUILD_DIR}/main run
setup:
mkdir -p ${BUILD_DIR}
mkdir -p ${OBJ}
ruby ../../scripts/create_makefile.rb --silent
clean:
rm -rf ${BUILD_DIR}
${BUILD_DIR}/main: ${SRC_DIR}/main.c ${SRC_DIR}/foo.c
${CC} $< -o $#
run:
./build/main || true
test: setup
-include ${TEST_MAKEFILE}
I found this was happening by finding that UNITY_LINE_TYPE was defined in unity.h and paid attention to how that unity.h was being included in my test, saw it was included after 'mock_foo.h' (no problem apparant to me yet), then compared to some working rake examples (in ../temp_sensor) where I noticed that all the 'unity.h' includes were before all the 'mock_xxx.h' includes (I hadn't touched these with vim yet.)
Don't let your tools be fools.
This bug has just been fixed: https://github.com/ThrowTheSwitch/CMock/pull/211
Now you do not need to keep specific order of #include directives.
Your mileage may vary, but I've found that grouping my includes with newlines causes clang-format to sort within the groups, thus allowing me to preserve important headers at the beginning. Usually this makes a certain logical sense as well.
So for instance, in my test_xyz.c file:
#include "unity.h"
#include "support/logging.h"
#include "crc.h"
#include "mock_unistd.h"
Gets sorted to:
#include "unity.h"
#include "crc.h"
#include "mock_unistd.h"
#include "support/logging.h"

GCC Linux C - Compile object header not found

I've been working on a module in C (under Linux) that requires another module (headers are in other directories).
My problem is that when I compile the code with my Makefile, the gcc compiler tells me that some headers aren't found.
gcc -c render.c
So I include the directories to find the header but here, gcc tries to find the "main" function which does not exist: it is a module...
gcc /opt/vc/include -c render.c
So I would like to know how is it possible to compile a module (output in module.o) that requires other modules?
Here are my files:
render.c:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "render.h"
int width,height;
int loop,counter;
int initRender(void(*setup)(void),void(*draw)(void),void(*end)(void))
{
init(&width, &height);
loop = -1;
counter = 0;
setup();
while(loop==-1)
{
Start(width, height);
draw();
End();
counter++;
}
end();
finish();
exit(0);
return 0;
}
render.h:
#include "VG/openvg.h"
#include "VG/vgu.h"
#include "fontinfo.h"
#include "shapes.h"
#ifndef RENDER_H_
#define RENDER_H_
extern int width,height;
extern int loop,counter;
int initRender(void(*setup)(void),void(*draw)(void),void(*end)(void));
#endif
Makefile:
INCLUDEFLAGS=-I/opt/vc/include -I/opt/vc/include/interface/vmcs_host/linux -I/opt/vc/include/interface/vcos/pthreads -IopenVG
LIBFLAGS=-L/opt/vc/lib -lGLESv2 -lEGL -lbcm_host -lpthread -ljpeg -LopenVG
NEEDED= openVG/libshapes.o openVG/oglinit.o
all: render
render.o: render.c
gcc -Wall -g $(INCLUDEFLAGS) -c render.c
You probably want
gcc -Wall -g -I/opt/vc/include -c render.c
this will produce a render.o object file.
Please take time to read the documentation about invoking GCC. In particular, check what every option -Wall, -g, -I and -c means. IMHO the first two are very important.
Later, you probably want to link all your object files into an executable, with some external libraries. Perhaps you want something like
gcc -g -Wall -L/opt/vc/lib render.o main.o -lvc -o myprogram
(you really want the -Wall and -g options; IMHO you need to be an expert to dare avoiding them; once you have debugged your program and want to benchmark it, add -O2 for optimizations)
But surely, you want other options.
Notice that order of arguments to gcc matters a lot
Of course, you should learn about GNU make and you need to use it. See this and that examples. You might use make --trace (with recent make) or remake to debug your Makefile (which is not good). You should also run once make -p to understand more the builtin rules of make.
Perhaps you want a library, then read the Program Library HowTo.

Ubuntu C program loadable module and undefined symbols

Very new to linux in general and trying to build a loadable module for use in zabbix, which works, but trying to build a simple shell program for testing it. That means this module needs to be loaded dynamically.
Sharable module SNMPmath is built with this:
gcc -shared -o SNMPmath.so $(CFLAGS) -I../../../include -I/usr/include/libxml2 -fPIC SNMPmath.c
That works fine for zabbix.
The test program (TestSO.c) uses
lib_handle = dlopen("./SNMPmath.so", RTLD_NOW);
to load this image dynamically, and when it does, it is missing symbols including init_snmp which come from the net-snmp package which is referenced in the SNMPmath loadable module.
My question is both general and specific. What's the right approach -- is this library called by the loadable module supposed to be forced into the loadable module? Is it supposed to be forced into the test program (despite having no compile-time reference to it)? Or is it supposed to be dynamically loaded, itself, in the loadable module (which seems to contradict what I'm seeing in other examples)?
And in either case, how is the GCC command modified to include net-snmp? I've tried variations of whole-archive, no-as-needed, listing what I think is the library (/usr/lib/x86_64-linux-gnu/libsnmp.a) with various compiler options with no effect (or occasionally errors). Also tried linking to the .so version of that (no effect). So a hint as to the proper GCC command to include the library would be very helpful.
Here's one iteration of attempts at linking the main program:
gcc -rdynamic -o TestSO -I../../../include -I/usr/include/libxml2 TestSO.c -ldl -Wl,--no-as-needed /usr/lib/x86_64-linux-gnu/libsnmp.so
I've found numerous examples of loading modules, but they all load a simple routine that does not itself have undefined symbols that need satisfying.
Recap:
TestSO.c
==> Loads with dlopen SNMPmath.c
==> needs to refer to net-snmp routines like init_snmp
Pointers to examples or explanation welcome, I realize I'm missing something fairly obvious.
EDIT AFTER FIRST COMMENTS TO INCLUDE:
I have it sort of working now, but would appreciate a sanity check if this is correct. I pruned it down so as to show the whole code. Here is the code to produce the SO:
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <string.h>
int zbx_module_SNMPmath_avg(int i, int j)
{
init_snmp("snmpapp"); // initialize SNMP library
return 1;
}
Here is how it is compiled (note slight name change):
CFLAGS=-I. `net-snmp-config --cflags`
SNMPmath_small: SNMPmath_small.c
gcc -shared -o SNMPmath.so $(CFLAGS) -I../../../include -I/usr/include/libxml2 -fPIC SNMPmath_small.c -Wl,--no-as-needed,/usr/lib/x86_64-linux-gnu/libsnmp.so
Then here is the main program:
#include <stdio.h>
#include <dlfcn.h>
#include <dlfcn.h>
#include <string.h>
int main(int argc, char **argv)
{
void *lib_handle;
int(*fn)(int req, int ret);
int x;
char *error;
lib_handle = dlopen("./SNMPmath.so", RTLD_NOW);
if (!lib_handle)
{
fprintf(stderr, "Error on open - %s\n", dlerror());
exit(1);
}
else
fprintf(stderr,"Successfully loaded module\n");
fn = dlsym(lib_handle, "zbx_module_SNMPmath_avg");
if ((error = dlerror()) != NULL)
{
fprintf(stderr, "Error on dlsym %s\n", error);
exit(1);
}
else fprintf(stderr,"Successfully called dlsym\n");
// testing
int req, ret;
req=1;
ret=1;
x=(*fn)(req, ret);
printf("Valx=%i\n",x);
dlclose(lib_handle);
return 0;
}
And finally this is built with:
TestSO: TestSO.c
gcc -rdynamic -o TestSO -I../../../include -I/usr/include/libxml2 TestSO.c -ldl
This now will run as expected. I found that linking against the netsnmp library's so file when building my so seemed to work.
But is this the correct sequence? And/or the preferred sequence?
Ps. Off to read the paper in the first proposed answer.
Pointer to explanation: Drepper's paper: Howto write shared libraries
But we need more source code (and the commands used to compile it), and the real error messages (e.g. as given by dlerror() after dlopen call) to help more.
(See also this answer)
You might want to add some libraries like -lsomething (I don't know which, you probably do know!) to your command gcc -shared which is building SNMPmath.so .... You don't want to link a static library like libsnmp.a to it (you should link shared libraries to your SNMPmath.so shared object).

C warning: implicit declaration of function

Yes, this question has been asked many times, and I've been looking and reading forums, and SO posts, but the answers are all unrelated (or so they seem) to this one. So, I have this main file :
-- sgbd_server.c --
#include "sgbd_server.h"
/**
* Open server pipe and return handle. -1 = error
*/
int open_server_pipe() {
return pipe_open(FIFO_NAME, O_RDONLY, S_CON_COLOR);
}
/**
* Close server pipe
*/
void close_server_pipe(int fd) {
pipe_close(fd, FIFO_NAME, S_CON_COLOR);
}
int main(int argc, char *argv[]) {
int pipe_fd;
pipe_fd = open_server_pipe();
if (pipe_fd == -1) {
perror("Cannot open pipe");
}
close_server_pipe(pipe_fd);
exit(EXIT_SUCCESS);
}
Then the header files :
-- sgbd_server.h --
#include "common.h"
#define FIFO_NAME "./sgbd_server_pipe"
#define BUFFER_SIZE PIPE_BUF
#define S_CON_COLOR 1 /* C_COLOR_RED */
-- common.h --
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "console.h"
#define CLIENT_FIFO_PREFIX = "./sgbd_client_"
int pipe_open(char *f, int mode, int color);
void pipe_close(int pipe_fd, char *f, int color);
The two functions pipe_open and pipe_close are defined in pipe.c and are basically returning 0 and void. This last file is compiled separately in the Make file.
I'm not a guru at making Make files, but for the sake of this question, here it is :
SERVER = sgbd_server
CLIENT = sgbd_client
CC = gcc
C_FLAGS = -Wall -I.
LINKER = gcc
L_FLAGS = -Wall -l pthread -Wall -I.
RM = rm -f
client: sgbd_client.o pipe.o console.o
#echo -n "Building client... "
#$(LINKER) $(L_FLAGS) -o $(CLIENT) sgbd_client.o pipe.o console.o
#echo "Complete!\n"
server: sgbd_server.o pipe.o console.o
#echo -n "Building server... "
#$(LINKER) $(L_FLAGS) -o $(SERVER) sgbd_server.o pipe.o console.o
#echo "Complete!\n"
sgbd_client.o: sgbd_client.c
#echo -n "Refreshing client sources... "
#$(CC) $(C_FLAGS) -c sgbd_client.c
#echo "Done!"
sgbd_server.o: sgbd_server.c common.h
#echo -n "Refreshing server sources..."
#$(CC) $(C_FLAGS) -c sgbd_server.c common.h
#echo "Done!"
pipe.o: pipe.c
#echo -n "Refreshing pipe sources..."
#$(CC) $(C_FLAGS) -c pipe.c
#echo "Done!"
console.o: console.c
#echo -n "Refreshing console sources..."
#$(CC) $(C_FLAGS) -c console.c
#echo "Done!"
clean:
#echo -n "Cleaning up executables and object files... "
#$(RM) $(SERVER) $(CLIENT) *.o
#echo "Ok\n"
** NOTE ** : the file console.c and implements some functions to control I/O on the console, nothing fancy. As you see, it is also compiled separately.
Now, when I type make client, all is well and birds are signing, etc. etc. But when I type make server, it spits out
sgbd_server.c: In function ‘open_server_pipe’:
sgbd_server.c:7: warning: implicit declaration of function ‘pipe_open’
sgbd_server.c: In function ‘close_server_pipe’:
sgbd_server.c:14: warning: implicit declaration of function ‘pipe_close’
I'm running GCC on a Linux amd64 if it makes any difference (I doubt it).
Now, why would it warn me about that? The two functions are declared in common.h, which is included in sgbd_server.h... What am I missing here?
Thank you for your time!
** UPDATE **
Thank you everyone for your suggestion. I did try to find if there would be a file common.h somewhere else in my include path that would be included somehow... While I failed to find any that would have slipped in the compilation process instead of the local common.h (sig) I found some .ghc files sitting in my source folder. Since they are not cleaned by make clean, I deleted manually those files. Guess what? No warning. What are those files and why are they created?
For a start, I don't think it's a good idea to be giving common.h to the compiler in the makefile:
#$(CC) $(C_FLAGS) -c sgbd_server.c common.h
This would be better as just:
#$(CC) $(C_FLAGS) -c sgbd_server.c
Header files are usually incorporated with just an #include. You appear to be telling the compiler to try and compile common.h as a standalone C file. That's one difference between the client and server compile commands and you should fix it.
The only other thing I can suggest is that you may not be getting the header files you think you're getting. Start by putting the line:
#error Urk! in common.h
at the top of your common.h and ensure the build fails there.
If not, then that file is coming from somewhere else. You may also want to do the same thing with your sgbd_server.h file as well.
Based on your edit:
I found some .ghc files sitting in my source folder. Since they are not cleaned by make clean, I deleted manually those files. Guess what? No warning. What are those files and why are they created?
These are, assuming ghc was a typo and you meant gch, pre-compiled headers generated by gcc, at least in part to speed up the compilation process. Rather than having to process a header file many times during a build (once per source file that includes it), pre-compiling it once and using the pre-compiled version is a lot more efficient.
I think this was most likely cause by the fact that you included common.h on your compiler command line when you did the server. By default, header files given directly to gcc will be turned into pre-compiled header files and used in preference after that point. To test this, I created a qq.h file and executed gcc qq.h and out popped qq.h.gch.
It's quite likely, given that deleting them solved your problem, that these files were somehow causing your issues (be that the presence of pre-compiled headers older than the real headers or something else entirely). There's a good chance that your compile line:
#$(CC) $(C_FLAGS) -c sgbd_server.c common.h
would first compile the server program, including the old precompiled header, then make a new precompiled header out of the newer header file.
That's probably why a change to common.h had no (immediate) effect. You would have to make ; touch common.h ; make to ensure the newer pre-compiled header file was used in the server program.
Whether you want to track it back to the root cause and get a proper explanation is a matter of taste - there's a school of thought that you should sometimes just record how you fixed it and not worry too much, lest you become entangled in the very nature of reality itself.
Not me of course, I'm the personality type that will attempt to track my problems back to the individual sub-atomic particle that caused it, but sometimes pragmatism requires me to let it go :-)
observations: you have an = in a #define which I suspect you don't mean to have there
#define CLIENT_FIFO_PREFIX = "./sgbd_client_"
should perhaps be
#define CLIENT_FIFO_PREFIX "./sgbd_client_"
comments: I've occasionally witnessed strange behavior from compilers when a prototype contains formal parameter names (in addition to the mandatory types) and the definition of the function uses different formal parameter names. ie. in your pipes.c Does you pipes.c
include common.h?
Also, conditional guards #ifndef headerfilename #define headerfilename #endif
are a good practise, but that is not directly related to your problem.
.PMCD.
I suspect you might have another file called common.h that's getting included instead of the file you expect. I copy and pasted your files and it compiled with no warning.
The includes in the files you posted look like they should work. A few ideas what else could be wrong:
Does common.h or console.h try to include sgbd_server.h, so that you end up with circular includes?
Do you use include guards (or even other #ifdefs) and maybe mixed them up somewhere, so that one of the files is excluded unintentionally?
Do you have another common.h somewhere in you include path that might get included instead of the one that you intended?

Resources