Related
Please consider the below code
shared.c
#include <stdio.h>
void printCharArray(char *someArray){
if (!someArray){
printf("someArray is null!\n");
} else {
printf("Array is %s\n", someArray);
}
}
and question.c:
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#define LIB "/tmp/some.so"
void *handle = 0;
void localfunc();
int main(){
handle = dlopen(LIB, RTLD_LAZY);
if (!handle){
fprintf(stderr, "dlopen err\n");
exit(1);
}
dlerror();
void (*printCharArray)() = dlsym(handle, "printCharArray");
char *err = dlerror();
if (err){
fprintf(stderr, "%s\n", err);
exit(1);
}
printCharArray(); // some work
localfunc();
}
void localfunc(){
puts("localfunc");
dlerror();
void (*printCharArray)() = dlsym(handle, "printCharArray"); // <- This
char *err = dlerror();
if (err){
fprintf(stderr, "%s\n", err);
exit(1);
}
printCharArray(); // do some work in localfunc
}
Compile and run
2035 gcc -shared -o /tmp/some.so shared.c -fPIC
2036 gcc -ldl question.c
$ ./a.out
someArray is null!
localfunc
someArray is null!
Notice how in localfunc I call dlsym again to import "printCharArray" which was previously done in main(). I am looking to avoid this - how can I make this method available after the 1st import? (iow, how can I make my 1st import to be available as a fn prototype for use anywhere in question.c?)
Declare the function pointer as a global variable, rather than local to main().
Give it the correct parameter declaration so the call matches the definition. And then call it with an argument.
There's no point in calling dlerror() before calling dlsym(). And it doesn't do anything useful if you don't assign the result to something.
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#define LIB "/tmp/some.so"
void *handle = 0;
void localfunc();
void (*printCharArray)(char *);
int main(){
handle = dlopen(LIB, RTLD_LAZY);
if (!handle){
fprintf(stderr, "dlopen err: %s\n", dlerror());
exit(1);
}
printCharArray = dlsym(handle, "printCharArray");
if (!printCharArray) {
char *err = dlerror();
printf(stderr, "%s\n", err);
exit(1);
}
printCharArray(NULL); // some work
localfunc();
}
void localfunc(){
puts("localfunc");
printCharArray("something"); // do some work in localfunc
}
I have just made a driver program, and when I execute make, it said
make error aliased to undefined symbol devone_init
I find many sites and cannot find the same error.Because I am new to
device programing , I am not clear about init_module.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/sched.h>
#include <asm/current.h>
#include <asm/uaccess.h>
MODULE_LICENCE("Dual BSD/GPL");
#define DRIVER_NAME "devone";
static int devone_devs = 2;
static int devone_major = 0;
module_param(devone_major. uint, 0);
static struct cdev devone_cdev;
static int devone_open(struct inode *inode, struct file *file)
{
printk("%s: major %d minor %d (pid %d)\n", __func__, imajor(inode), iminor(inode), current->pid);
inode->i_private = inode;
file->private_data = file;
printk("i_private=%p private_data=%p\n", inode->i_private, file->private_data);
return 0;
}
static int devone_close(struct inode *inode, struct file *file)
{
printk("%s: major %d minor %d (pid %d)\n", __func__, imajor(inode), iminor(inode), current->pid);
inode->i_private = inode;
file->private_data = file;
printk("i_private=%p private_data=%p\n", inode->i_private, file->private_data);
return 0;
}
struct file_operations devone_fops = {
.open = devone_opens;
.release = devone_close;
}
static int devone_init(void)
{
dev_t dev = MKDEV(devone_major, 0);
int alloc_ret = 0;
int major;
int cdev_err = 0;
alloc_ret = alloc_chrdev_region(&dev, 0, devone_devs, DRIVER_NAME);
if(alloc_ret)
goto error;
devone_major = major = MAJOR(dev);
cdev_init(&devone_cdev, &devone_fops);
devone_cdev.owner = THIS_MODULE;
cdev_err = cdev_add(&devone_cdev, MKDEV(devone_major, 0), devone_devs);
if(cdev_err)
goto error;
printk(KERN_ALERT "%s driver(%d) loaded\n", DRIVER_NAME, major);
return 0;
error:
if(cdev_err == 0)
cdev_del(devone_cdev);
if(alloc_ret == 0)
unregister_chrdev_region(dev, devone_devs);
return -1;
}
static void devone_exit(void)
{
dev_t dev = MKDEV(devone_major, 0);
cdev_del(&devone_cdev);
cdev_del(&devone_cdev);
unregister_chrdev_region(dev, devone_devs);
printk(KERN_ALERT "%s driver unloaded\n", DRIVER_NAME);
}
module_init(devone_init);
module_exit(devone_exit);
here is my makefile.When I add cflags , it returned cflags was changed.
#CFLAGS += -Wall
CFILES = devone.c
obj-m += sample.o
KDIR =/lib/modules/$(shell uname -r)/build
sample-objs := $(CFILES:.c=.o)
all:
$(MAKE) -C $(KDIR) M=$(shell pwd) modules
clean:
rm -rf *.o *.ko *.mod.* *.symvers *.order
There are several minute problems in the code which is preventing it from compilation. Modified code which compiles properly is below. you can compare and find out the diff.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/sched.h>
#include <asm/current.h>
#include <asm/uaccess.h>
#define DRIVER_NAME "devone"
static int devone_devs = 2;
static int devone_major = 0;
module_param(devone_major, uint, 0);
static struct cdev devone_cdev;
static int devone_open(struct inode *inode, struct file *file)
{
printk("%s: major %d minor %d (pid %d)\n", __func__, imajor(inode), iminor(inode), current->pid);
inode->i_private = inode;
file->private_data = file;
printk("i_private=%p private_data=%p\n", inode->i_private, file->private_data);
return 0;
}
static int devone_close(struct inode *inode, struct file *file)
{
printk("%s: major %d minor %d (pid %d)\n", __func__, imajor(inode), iminor(inode), current->pid);
inode->i_private = inode;
file->private_data = file;
printk("i_private=%p private_data=%p\n", inode->i_private, file->private_data);
return 0;
}
struct file_operations devone_fops = {
.open = devone_open,
.release = devone_close,
};
static int devone_init(void)
{
dev_t dev = MKDEV(devone_major, 0);
int alloc_ret = 0;
int major;
int cdev_err = 0;
alloc_ret = alloc_chrdev_region(&dev, 0, devone_devs, DRIVER_NAME);
if(alloc_ret)
goto error;
devone_major = major = MAJOR(dev);
cdev_init(&devone_cdev, &devone_fops);
devone_cdev.owner = THIS_MODULE;
cdev_err = cdev_add(&devone_cdev, MKDEV(devone_major, 0), devone_devs);
if(cdev_err)
goto error;
printk(KERN_ALERT "%s driver(%d) loaded\n", DRIVER_NAME, major);
return 0;
error:
if(cdev_err == 0)
cdev_del(&devone_cdev);
if(alloc_ret == 0)
unregister_chrdev_region(dev, devone_devs);
return -1;
}
static void devone_exit(void)
{
dev_t dev = MKDEV(devone_major, 0);
cdev_del(&devone_cdev);
cdev_del(&devone_cdev);
unregister_chrdev_region(dev, devone_devs);
printk(KERN_ALERT "%s driver unloaded\n", DRIVER_NAME);
}
module_init(devone_init);
module_exit(devone_exit);
MODULE_LICENSE("Dual BSD/GPL");
I try to use libfuse (cuse) to create character device and play on it like with regular tty, all is fine till I use tcgetattr.
Unfortunately, termios.tcgetattr() always raise I/O error.
cusetest.c
#define FUSE_USE_VERSION 29
#define _FILE_OFFSET_BITS 64
#include <fuse/cuse_lowlevel.h>
#include <fuse/fuse_opt.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
//#include <termios.h>
#include <linux/termios.h>
#include <unistd.h>
#include <stdlib.h>
#include <strings.h>
#include <errno.h>
#define LOG(...) do { fprintf(stderr, "DEBUG: "__VA_ARGS__); puts(""); } while (0)
static void cusetest_open(fuse_req_t req, struct fuse_file_info *fi) {
LOG("cusetest_open called\n");
fuse_reply_open(req, fi);
}
static void cusetest_read(fuse_req_t req, size_t size, off_t off, struct fuse_file_info *fi) {
LOG("cusetest_read called\n");
fuse_reply_buf(req, "Hello", size > 5 ? 5 : size);
}
static void cusetest_write(fuse_req_t req, const char *buf, size_t size, off_t off, struct fuse_file_info *fi) {
LOG("cusetest_write called, size: %lu bytes\n", size);
fuse_reply_write(req, size);
}
static void cusetest_ioctl(fuse_req_t req, int cmd, void *arg, struct fuse_file_info *fi, unsigned flags, const void *in_buf, size_t in_bufsz, size_t out_bufsz) {
LOG("cusetest_ioctl called, cmd: %d insize: %lu outsize: %lu\n", cmd, in_bufsz, out_bufsz);
struct termios oldtio;
int i;
oldtio.c_iflag = 1;
oldtio.c_oflag = 2;
oldtio.c_cflag = 3;
oldtio.c_lflag = 4;
for (i = 0; i < NCCS; ++i)
{
oldtio.c_cc[i] = i;
}
printf("NCCS:%ud\n\n", NCCS);
printf("c_iflag:%ud \n", oldtio.c_iflag);
printf("c_oflag:%ud\n", oldtio.c_oflag);
printf("c_cflag:%ud\n", oldtio.c_cflag);
printf("c_lflag:%ud\n", oldtio.c_lflag);
// printk("c_ispeed:%ud\n", oldtio.ispeed);
// printk("c_ospeed:%ud\n\n", oldtio.c_ospeed);
for (i = 0; i < NCCS; ++i)
{
printf("CC: %d\n", oldtio.c_cc[i]);
}
printf("\n");
fuse_reply_ioctl(req, 21506, &oldtio, sizeof(oldtio));
}
static const struct cuse_lowlevel_ops cusetest_clop = {
.open = cusetest_open,
.read = cusetest_read,
.write = cusetest_write,
.ioctl = cusetest_ioctl,
};
struct cuse_info2 {
unsigned int dev_major;
unsigned int dev_minor;
unsigned int dev_info_argc;
char ** dev_info_argv;
unsigned int flags;
};
// char * argv[] == char ** argv
int main(int argc, char** argv) {
// -f: run in foreground, -d: debug ouput
// Compile official example and use -h
const char* cusearg[] = {"test", "-f", "-d"};
const char* devarg[] = {"DEVNAME=ttyCUSE0" };
struct cuse_info ci;
memset(&ci, 0x00, sizeof(ci));
ci.flags = CUSE_UNRESTRICTED_IOCTL;
ci.dev_info_argc=1;
ci.dev_info_argv = devarg;
//int cuse_lowlevel_main(int argc, char *argv[], const struct cuse_info *ci, const struct cuse_lowlevel_ops *clop, void *userdata);
return cuse_lowlevel_main(3, (char**) &cusearg, &ci, &cusetest_clop, NULL);
}
Here I use the same code (structure) in kernel module, and all is fine:
ttymodule.c:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/termios.h>
#include <linux/errno.h>
#define DEVICE_NAME "ttytest"
#define CLASS_NAME "ttytest"
static int major;
static struct class* tty_class = NULL;
static struct device* tty_device = NULL;
static long fake_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg){
struct termios oldtio;
int i;
oldtio.c_iflag = 1;
oldtio.c_oflag = 2;
oldtio.c_cflag = 3;
oldtio.c_lflag = 4;
for (i = 0; i < NCCS; ++i)
{
oldtio.c_cc[i] = i;
}
printk(KERN_ALERT "ttytest: ioctl called: %d -> %ld \n", cmd_in, arg);
printk(KERN_ALERT "NCCS:%ud\n\n", NCCS);
printk(KERN_ALERT "c_iflag:%ud \n", oldtio.c_iflag);
printk(KERN_ALERT "c_oflag:%ud\n", oldtio.c_oflag);
printk(KERN_ALERT "c_cflag:%ud\n", oldtio.c_cflag);
printk(KERN_ALERT "c_lflag:%ud\n", oldtio.c_lflag);
//printk(KERN_ALERT "c_ispeed:%ud\n", oldtio.ispeed);
//printk(KERN_ALERT "c_ospeed:%ud\n\n", oldtio.c_ospeed);
for (i = 0; i < NCCS; ++i)
{
printk(KERN_ALERT "CC: %d\n", oldtio.c_cc[i]);
}
printk(KERN_ALERT "\n");
return cmd_in+1;
}
static struct file_operations fops =
{
.owner = THIS_MODULE,
.unlocked_ioctl = fake_ioctl
};
static int __init tty_init(void){
printk(KERN_INFO "ttytest: Initializing ...\n");
major = register_chrdev(0, DEVICE_NAME, &fops);
if (major<0){
printk(KERN_ALERT "ttytest failed to register a major number\n");
return major;
}
tty_class = class_create(THIS_MODULE, CLASS_NAME);
if (IS_ERR(tty_class)){
unregister_chrdev(major, DEVICE_NAME);
printk(KERN_ALERT "Failed to register device class\n");
return PTR_ERR(tty_class);
}
tty_device = device_create(tty_class, NULL, MKDEV(major, 0), NULL, DEVICE_NAME);
if (IS_ERR(tty_device)){
class_destroy(tty_class);
unregister_chrdev(major, DEVICE_NAME);
printk(KERN_ALERT "Failed to create the device\n");
return PTR_ERR(tty_device);
}
return 0;
}
static void __exit tty_exit(void){
device_destroy(tty_class, MKDEV(major, 0));
class_unregister(tty_class); // unregister the device class
class_destroy(tty_class); // remove the device class
unregister_chrdev(major, DEVICE_NAME); // unregister the major number
printk(KERN_INFO "ttytest: Goodbye ...\n");
}
module_init(tty_init);
module_exit(tty_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Grzegorz Hetman");
MODULE_DESCRIPTION("A simple tty module to test cuse implementation.");
MODULE_VERSION("0.1");
Makefile:
obj-m := ttymodule.o
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all: unload clean
$(MAKE) -C $(KERNELDIR) M=$(PWD)
#make load
#make cuse
#sudo ./cusetest
clean:
#rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c *.order *.symvers cusetest
load:
#sudo insmod ttymodule.ko
#sudo chmod 777 /dev/ttytest
#sudo lsmod |grep ttymodule
unload:
#sudo rmmod ttymodule || true
#sudo rm -f /dev/ttymodule
cuse:
#gcc -Wall -g cusetest.c -lfuse -o cusetest
Result(for eg in python):
import termios
termios.tcgetattr(open('/dev/ttyCUSE0','rw+')) # error: (5, 'Input/output error')
termios.tcgetattr(open('/dev/ttytest','rw+')) # [5523920, 0, 1576586344, 32702, 8, 8, ['\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '#', 'r', '\x90', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'g', '\x82', '\x01', '\x00', '\x00', '\x00', '\x00', ',', 'h', 'K', '\x00', '\x00', '\x00', '\x00', '\x00', '\x90']]
As far as I know, cuse drivers aren't like regular tty drivers because they aren't terminal drivers. They are user space character oriented file system drivers.
In order to play with it as you want, it should be under the tty components like below image (Taken from LDD3). Same source as the image describes how to create terminal derivers.
By the way, there is no userspace tty driver I know.
Trying to compile an example of wrapping library from here
I had to include stdio.h and stdlib.h, and came to that code:
#define _GNU_SOURCE
#define _USE_GNU
#include <signal.h>
#include <execinfo.h>
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>
static void show_stackframe() {
void *trace[16];
char **messages = (char **)NULL;
int i, trace_size = 0;
trace_size = backtrace(trace, 16);
messages = backtrace_symbols(trace, trace_size);
printf("[bt] Execution path:\n");
for (i=0; i < trace_size; ++i)
printf("[bt] %s\n", messages[i]);
}
int ioctl(int fd, int request, void *data)
{
char *msg;
if (next_ioctl == NULL) {
fprintf(stderr, "ioctl : wrapping ioctl\n");
fflush(stderr);
// next_ioctl = dlsym((void *) -11, /* RTLD_NEXT, */ "ioctl");
next_ioctl = dlsym(RTLD_NEXT, "ioctl");
fprintf(stderr, "next_ioctl = %p\n", next_ioctl);
fflush(stderr);
if ((msg = dlerror()) != NULL) {
fprintf(stderr, "ioctl: dlopen failed : %s\n", msg);
fflush(stderr);
exit(1);
} else
fprintf(stderr, "ioctl: wrapping done\n");
fflush(stderr);
}
if (request == 1) { /* SCSI_IOCTL_SEND_COMMAND ? */
/* call back trace */
fprintf(stderr, "SCSI_IOCTL_SEND_COMMAND ioctl\n");
fflush(stderr);
show_stackframe();
}
return next_ioctl(fd, request, data);
}
and Makefile
#
# Makefile
#
all: libs test_ioctl
libs: libwrap_ioctl.so
libwrap_ioctl.so: wrap_ioctl.c
rm -f libwrap_ioctl.so*
gcc -fPIC -shared -Wl,-soname,libwrap_ioctl.so.1 -ldl -o libwrap_ioctl.so.1.0 wrap_ioctl.c
ln -s libwrap_ioctl.so.1.0 libwrap_ioctl.so.1
ln -s libwrap_ioctl.so.1 libwrap_ioctl.so
clean:
rm -f libwrap_ioctl.so* test_ioctl
and stuck in these errors, despite dlfcn.h is included.
~/my_src/native/glibc_wrapper > make
rm -f libwrap_ioctl.so*
gcc -fPIC -shared -Wl,-soname,libwrap_ioctl.so.1 -ldl -o libwrap_ioctl.so.1.0 wrap_ioctl.c
wrap_ioctl.c: In function ‘ioctl’:
wrap_ioctl.c:26: error: ‘next_ioctl’ undeclared (first use in this function)
wrap_ioctl.c:26: error: (Each undeclared identifier is reported only once
wrap_ioctl.c:26: error: for each function it appears in.)
make: *** [libwrap_ioctl.so] Ошибка 1
dlfcn.h itself doesn't define any symbol with name next_smth. (In SUS, dlfcn.h only defines several dl* functions and RTLD_ macro: http://pubs.opengroup.org/onlinepubs/7908799/xsh/dlfcn.h.html)
You should define this as pointer to function in your program code in explicit way. Something like this: (taken from https://port70.net/svn/misc/remac/remac.c or from https://github.com/itm/forward-sensor/blob/master/preload.c or ... any google search for "next_ioctl"):
static int (*next_ioctl) (int fd, int request, void *data) = NULL;
Or, if you want a collective blog-reading session, there is additional line in the blog post with ioctl overloading: http://scaryreasoner.wordpress.com/2007/11/17/using-ld_preload-libraries-and-glibc-backtrace-function-for-debugging/ (just before first huge code fragment)
Then, declare a function pointer to hold the value
of the “real” ioctl() function from glibc:
static int (*next_ioctl)(int fd, int request, void *data) = NULL;
Then declare your replacement ioctl function:
You missed to declare next_ioctl.
Just add
void * next_ioctl = NULL;
int (*next_ioctl) (int, int, ...) = NULL;
to main().
I have to compile two independent processes-sendfdsock.c and recvfdsock.c using make file. Both the files have there own main function. This means they are independent and I have to compile them as two different binaries. This is my make file:
compileAll:sendfdsock recvfdsock
sendfdsock:sendfdsock.o
gcc -o sendfdsock sendfdsock.o
sendfdsock.o:sendfdsock.c accessories.h
gcc -c sendfdsock.c
recvfdsock.o:recvfdsock.c accessories.h
gcc -c recvfdsock.c
recvfdsock:recvfdsock.o
gcc -o recvfdsock recvfdsock.o
Here I have made a compileAll target which compiles both the files.
Both files need to use accessories.h. As mention in GNU Make Doc - A simple Make file. I wrote this make file.
accessories.h :
#include <malloc.h>
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <error.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/un.h>
#include <stropts.h>
#define PORT "4444" //port we are listening on
int sendall(int fd, char *buf, int *len);
int recvall(int fd, char *buf, int *len);
void logp(int typ, char* msg);
void errorp(char *where, int boolean, int errn,char *what);
accessories.c :
#include "accessories.h"
void logp(int typ, char* msg) // typ --> type(category) of message [1-Normal Log, 2-Warning(any unexpected thing happened), 3-Error, 4-Debugging Log ]
{
int fd;
time_t now;
ssize_t wlength=0;
char * dat;
char * str;
int size = 45+strlen(msg);//14+24+5+sizeof msg+1
str= (char *) malloc(size);
time(&now);//system time in seconds
dat = ctime(&now); // converting seconds to date-time format
dat = strtok(dat,"\n");
//Appending type of log
switch(typ)
{
case 1:
strcpy(str,"__LOG__ | ");
strcat(str,dat);
break;
case 2:
strcpy(str,"__WARN__ | ");
strcat(str,dat);
break;
case 3:
strcpy(str,"__ERR__ | ");
strcat(str,dat);
break;
case 4:
strcpy(str,"__DEBUG__ | ");
strcat(str,dat);
break;
default:
strcpy(str,"__UNDEF__ | ");
strcat(str,dat);
break;
}
strcat(str," | ");
strcat(str,msg);//appending message
strcat(str,"\n");
fd = open("log", O_WRONLY | O_CREAT | O_APPEND, 0644); // should be opened somewhere else
if (fd == -1)
printf("Could not open log - %s\n",strerror(errno));
else
{//need to add lock to the file and printing error message
while ( wlength < strlen(str) )
{
wlength = write(fd, str,strlen(str));
if (wlength == -1)
{
printf("Error : writing log\n");
break;
}
}
}
}
int sendall(int fd, char *buf, int *len)
{
int total = 0; // how many bytes we've sent
int bytesleft = *len; // how many we have left to send
int n;
while(total < *len) {
n = send(fd, buf+total, bytesleft, 0);
if (n == -1) { break; }
total += n;
bytesleft -= n;
}
*len = total; // return number actually sent here
return n==-1?-1:0; // return -1 on failure, 0 on success
}
int recvall(int fd, char *buf, int *len)
{
int total = 0; // how many bytes we've sent
int bytesleft = *len; // how many we have left to send
int n;
while(total < *len) {
n = recv(fd, buf+total, bytesleft, 0);
if (n == -1) { break; }
total += n;
bytesleft -= n;
}
*len = total; // return number actually sent here
return n==-1?-1:0; // return -1 on failure, 0 on success
}
void errorp(char *where, int boolean, int errn,char *what)
{
char errmsg[21+strlen(where)];
strcpy(errmsg,"Where - ");
strcat(errmsg,where);
strcat(errmsg," | Error - ");
if(boolean == 1)//we got error number
{
strcat(errmsg,strerror(errn));
//fprintf(stderr,"ERROR - In %s and error is %s\n",where ,strerror(errn));
logp(3,errmsg);
}
else if(boolean == 0)//we got a message
{
strcat(errmsg,what);
//fprintf(stderr,"ERROR - In %s and error is %s\n",where ,what);
logp(3,errmsg);
}
else//we got nothing
{
strcat(errmsg,"No Message");
//fprintf(stderr,"ERROR - In %s\n",where);
logp(3,errmsg);
}
}
Initially everything work fine but when I trid to use any function which is defined in accessories.c compilation give me error.
For example I use the log function in sendfdsock.c :
#include "accessories.h"
#define CONTROLLEN CMSG_LEN(sizeof(int))
static struct cmsghdr *cmptr = NULL; /* malloc'ed first time */
int send_err(int fd, int errcode, const char *msg);
int send_fd(int fd, int fd_to_send);
int main(int argc, char const *argv[])
{
logp(1,"started"); //This function is defined in accessories.c
int fd_to_send;
if((fd_to_send = open("vi",O_RDONLY)) < 0)
printf("vi open failed");
struct sockaddr_un address;
int socket_fd, nbytes;
char buffer[256];
........
Output of the compilation is:
abhi#abhi-me:~/bridge/server$ make compileAll
gcc -c sendfdsock.c
sendfdsock.c: In function ‘send_fd’:
sendfdsock.c:111:9: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘ssize_t’ [-Wformat]
sendfdsock.c:114:5: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘ssize_t’ [-Wformat]
gcc -o sendfdsock sendfdsock.o
sendfdsock.o: In function `main':
sendfdsock.c:(.text+0x32): undefined reference to `logp'
collect2: ld returned 1 exit status
make: *** [sendfdsock] Error 1
abhi#abhi-me:~/bridge/server$
Why undefined reference to logp error?
Why I don't write accessories.o in final linking:
But as this example is given in GNU Make Doc:
In this example, all the C files include ‘defs.h’, but
only those defining editing comminclude ‘command.h’, and only
low level files that change the editor buffer include 'buffer.h':
edit : main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
cc -o edit main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
main.o : main.c defs.h
cc -c main.c
kbd.o : kbd.c defs.h command.h
cc -c kbd.c
command.o : command.c defs.h command.h
cc -c command.c
display.o : display.c defs.h buffer.h
cc -c display.c
insert.o : insert.c defs.h buffer.h
cc -c insert.c
search.o : search.c defs.h buffer.h
cc -c search.c
files.o : files.c defs.h buffer.h command.h
cc -c files.c
utils.o : utils.c defs.h
cc -c utils.c
clean :
rm edit main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
Here while linking all the files in edit they don't write defs.o or buffer.o. Means while linking they are not including object files of header files. Also they have not written any target like: defs.o or buffer.o
Why?
You just missed accessories.o in both linking targets. Something like this:
accessories.o: accessories.c
sendfdsock: sendfdsock.o accessories.o
$(CC) -o $# $(CFLAGS) $(LDFLAGS) $+
Also, consider using the built-in rules, just modify their parameters, if needed. See make -p for the full list (and makes infopage)
You misunderstand the relationship between source files, header files and object files.
Suppose I have the following four files:
//foo.h
#define PI 3.1
//bar.h
void func();
//bar.c
#include "foo.h"
#include "bar.h"
void func()
{
...
}
//baz.c
#include "foo.h"
#include "bar.h"
int main()
{
func();
}
(I left out the header guards, I presume you know about those.) I must use the compiler to produce an object file from each source file: bar.c -> bar.o and baz.c -> baz.o. I don't have to make object files from the headers foo.h and bar.h, those will simply be #included by any source file that needs them. Then I link the object files together to form an executable:
baz: bar.o baz.o
gcc -o baz bar.o baz.o
bar.o: bar.c foo.h bar.h
gcc -c bar.c
baz.o: baz.c foo.h bar.h
gcc -c baz.c
If I neglect to link bar.o into the executable, I'll get a linker error when the linker gets to the place where baz calls func() and the linker doesn't know what to put there (because it lacks the definition of func() in bar.o):
baz.o: In function `main':
baz.c:(.text+0x32): undefined reference to `func()'
So the GNU Make doc is correct, and as Alex said, your rule should have:
sendfdsock:sendfdsock.o accessories.o
...
accessories.o: accessories.c accessories.h
...
(Incidentally, once you get this makefile working, we can show you how to make it more concise.)