PDA

View Full Version : linking user space and kernel space programs with qmake



zielchri
8th March 2006, 19:56
I posted a message on qtforum.org, but nobody's responded yet so I'm hoping somebody in this forum can help me instead. The following is the thread I posted there:
---------------------------------------------------------------------------------------------------------

Guys,

I'm working in a research lab at Michigan State University on a project that we would like to see use a GUI on our linux real-time box. Currently I can write a command prompt program which uses RTAI and comedi, and I can write a makefile that will compile the user space program to link to the kernel space program. For qt, I can write a GUI program which compiles just fine when I use qmake by itself.

However, I can't seem to copy and paste the user space program into the qt program (since qt is user space), and then run qmake with the right include files and directorys to actually compile the program. At the moment, it's giving me errors about the kernel space program so I think the user space program works just fine.

So my question is this: How do you link a user space program to a kernel space program using qmake? My operating system is SUSE Linux PRO 9.0, using qt3. The .pro file is below

################################################## #########################
################################################## #########################
TARGET= KDEMenu
MOC_DIR = src/moc #added
OBJECTS_DIR = obj #added
INCLUDEPATH = /opt/kde3/include
INCLUDEPATH += /usr/lib/qt3/include #added
INCLUDEPATH += /usr/src/linux/include #added recently
INCLUDEPATH += /usr/realtime/include #added recently
INCLUDEPATH += /devel/comedi-0.7.68/include #added recently
QMAKE_LIBDIR_X11 += /opt/kde3/lib
QMAKE_LIBDIR_X11 += /usr/lib #added
QMAKE_LIBS_X11 += -lkdeui -lkdecore
FLAGS=-g -D__KERNEL__ -DMODULE -O2 #added
SOURCES = KDEMenu.cpp RT_DAQ.c
HEADERS = KDEMenu.h
CONFIG = qt opengl dll rtti debug
################################################## #########################
################################################## #########################

The make file generated by this is as follows:

################################################## #########################
################################################## #########################
# Makefile for building: KDEMenu
# Generated by qmake (1.06c) (Qt 3.2.1) on: Tue Mar 7 15:56:01 2006
# Project: menu.pro
# Template: app
# Command: $(QMAKE) -o Makefile menu.pro
################################################## #########################

####### Compiler, tools and options

CC = gcc
CXX = g++
LEX = flex
YACC = yacc
CFLAGS = -pipe -O2 -march=i586 -mcpu=i686 -fmessage-length=0 -fPIC -g
CXXFLAGS = -pipe -O2 -march=i586 -mcpu=i686 -fmessage-length=0 -fPIC -g
LEXFLAGS =
YACCFLAGS= -d
INCPATH = -I/usr/lib/qt3/mkspecs/default -I. -I/opt/kde3/include -I/usr/lib/qt3/include -I/usr/src/linux-2.4.25/include -I/usr/realtime/include -I/devel/comedi-0.7.68/include -I/usr/include -I$(QTDIR)/include -I/usr/include -I/usr/X11R6/include -Isrc/moc/
LINK = g++
LFLAGS =
LIBS = $(SUBLIBS) -L/usr/lib/ -L$(QTDIR)/lib/ -L/usr/lib/ -L/usr/X11R6/lib/ -L/opt/kde3/lib -L/usr/lib -lqt -lGLU -lGL -lXmu -lXext -lX11 -lm -lkdeui -lkdecore
AR = ar cqs
RANLIB =
MOC = $(QTDIR)/bin/moc
UIC = $(QTDIR)/bin/uic
QMAKE = qmake
TAR = tar -cf
GZIP = gzip -9f
COPY = cp -f
COPY_FILE= $(COPY)
COPY_DIR = $(COPY) -r
DEL_FILE = rm -f
SYMLINK = ln -sf
DEL_DIR = rmdir
MOVE = mv -f
CHK_DIR_EXISTS= test -d
MKDIR = mkdir -p

####### Output directory

OBJECTS_DIR = obj/

####### Files

HEADERS = KDEMenu.h
SOURCES = KDEMenu.cpp \
RT_DAQ.c
OBJECTS = obj/KDEMenu.o \
obj/RT_DAQ.o
FORMS =
UICDECLS =
UICIMPLS =
SRCMOC = src/moc/moc_KDEMenu.cpp
OBJMOC = obj/moc_KDEMenu.o
DIST = menu.pro
QMAKE_TARGET = KDEMenu
DESTDIR =
TARGET = KDEMenu

first: all
####### Implicit rules

.SUFFIXES: .c .o .cpp .cc .cxx .C

.cpp.o:
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<

.cc.o:
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<

.cxx.o:
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<

.C.o:
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<

.c.o:
$(CC) -c $(CFLAGS) $(INCPATH) -o $@ $<

####### Build rules

all: Makefile $(TARGET)

$(TARGET): $(UICDECLS) $(OBJECTS) $(OBJMOC)
$(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJMOC) $(LIBS) $(OBJCOMP)

mocables: $(SRCMOC)
uicables: $(UICDECLS) $(UICIMPLS)

$(MOC):
( cd $(QTDIR)/src/moc ; $(MAKE) )

Makefile: menu.pro /usr/lib/qt3/mkspecs/default/qmake.conf
$(QMAKE) -o Makefile menu.pro
qmake:
@$(QMAKE) -o Makefile menu.pro

dist:
@mkdir -p obj/KDEMenu && $(COPY_FILE) --parents $(SOURCES) $(HEADERS) $(FORMS) $(DIST) obj/KDEMenu/ && ( cd `dirname obj/KDEMenu` && $(TAR) KDEMenu.tar KDEMenu && $(GZIP) KDEMenu.tar ) && $(MOVE) `dirname obj/KDEMenu`/KDEMenu.tar.gz . && $(DEL_FILE) -r obj/KDEMenu

mocclean:
-$(DEL_FILE) $(OBJMOC)
-$(DEL_FILE) $(SRCMOC)

uiclean:

yaccclean:
lexclean:
clean: mocclean
-$(DEL_FILE) $(OBJECTS)
-$(DEL_FILE) *~ core *.core


####### Sub-libraries

distclean: clean
-$(DEL_FILE) $(TARGET) $(TARGET)


FORCE:

####### Compile

obj/KDEMenu.o: KDEMenu.cpp KDEMenu.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o obj/KDEMenu.o KDEMenu.cpp

obj/RT_DAQ.o: RT_DAQ.c
$(CC) -c $(CFLAGS) $(INCPATH) -o obj/RT_DAQ.o RT_DAQ.c

obj/moc_KDEMenu.o: src/moc/moc_KDEMenu.cpp KDEMenu.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o obj/moc_KDEMenu.o src/moc/moc_KDEMenu.cpp

src/moc/moc_KDEMenu.cpp: $(MOC) KDEMenu.h
$(MOC) KDEMenu.h -o src/moc/moc_KDEMenu.cpp

####### Install

install: all

uninstall:

################################################## #######################
################################################## #######################

The user space program is KDEMenu.cpp, which is an offshoot of an example on qt's website, and the kernel space program is RT_DAQ.c

The following is the error messages I get when I run "QTDIR=/usr/lib/qt3 make"

obj/RT_DAQ.o(.text+0x26): In function `set_volts':
/root/test/RT_DAQ.c:61: undefined reference to `printk'
obj/RT_DAQ.o(.text+0x2b):/root/test/RT_DAQ.c:62: undefined reference to `rt_task_wait_period'
obj/RT_DAQ.o(.text+0x39):/root/test/RT_DAQ.c:102: undefined reference to `rt_task_wait_period'
obj/RT_DAQ.o(.text+0x5a):/root/test/RT_DAQ.c:92: undefined reference to `rt_get_cpu_time_ns'
obj/RT_DAQ.o(.text+0xd2):/root/test/RT_DAQ.c:93: undefined reference to `comedi_data_write'
obj/RT_DAQ.o(.text+0xe6):/root/test/RT_DAQ.c:94: undefined reference to `rt_sleep'
obj/RT_DAQ.o(.text+0x11e):/root/test/RT_DAQ.c:95: undefined reference to `comedi_data_read'
obj/RT_DAQ.o(.text+0x123):/root/test/RT_DAQ.c:96: undefined reference to `rt_get_time_ns'
obj/RT_DAQ.o(.text+0x141):/root/test/RT_DAQ.c:99: undefined reference to `rtf_put'
obj/RT_DAQ.o(.text+0x15c):/root/test/RT_DAQ.c:100: undefined reference to `rtf_put'
obj/RT_DAQ.o(.text+0x18e): In function `init_module':
/root/test/RT_DAQ.c:108: undefined reference to `printk'
obj/RT_DAQ.o(.text+0x193):/root/test/RT_DAQ.c:109: undefined reference to `rt_get_time'
obj/RT_DAQ.o(.text+0x1b5):/root/test/RT_DAQ.c:113: undefined reference to `rt_shm_alloc'
obj/RT_DAQ.o(.text+0x1d4):/root/test/RT_DAQ.c:115: undefined reference to `comedi_open'
obj/RT_DAQ.o(.text+0x21d):/root/test/RT_DAQ.c:116: undefined reference to `rt_task_init'
obj/RT_DAQ.o(.text+0x254):/root/test/RT_DAQ.c:117: undefined reference to `rt_task_init'
obj/RT_DAQ.o(.text+0x26cool :/root/test/RT_DAQ.c:118: undefined reference to `rtf_create'
obj/RT_DAQ.o(.text+0x27c):/root/test/RT_DAQ.c:119: undefined reference to `rtf_create'
obj/RT_DAQ.o(.text+0x290):/root/test/RT_DAQ.c:120: undefined reference to `nano2count'
obj/RT_DAQ.o(.text+0x29cool :/root/test/RT_DAQ.c:120: undefined reference to `start_rt_timer'
obj/RT_DAQ.o(.text+0x2ce):/root/test/RT_DAQ.c:121: undefined reference to `rt_task_make_periodic'
obj/RT_DAQ.o(.text+0x307): In function `cleanup_module':
/root/test/RT_DAQ.c:128: undefined reference to `comedi_close'
obj/RT_DAQ.o(.text+0x30c):/root/test/RT_DAQ.c:129: undefined reference to `stop_rt_timer'
obj/RT_DAQ.o(.text+0x31cool :/root/test/RT_DAQ.c:130: undefined reference to `rt_busy_sleep'
obj/RT_DAQ.o(.text+0x320):/root/test/RT_DAQ.c:131: undefined reference to `rt_task_delete'
obj/RT_DAQ.o(.text+0x32c):/root/test/RT_DAQ.c:132: undefined reference to `rt_shm_free'
obj/RT_DAQ.o(.text+0x33cool :/root/test/RT_DAQ.c:133: undefined reference to `rtf_destroy'
obj/RT_DAQ.o(.text+0x344):/root/test/RT_DAQ.c:134: undefined reference to `rtf_destroy'
obj/RT_DAQ.o(.text+0x34c):/root/test/RT_DAQ.c:135: undefined reference to `rt_task_delete'
collect2: ld returned 1 exit status
make: *** [KDEMenu] Error 1

As you can see, the makefile isn't able to find rtai or comedi functions even though I'm including then in the makefile. I don't understand what the problem is, but that's probably because I'm new to qt. Any help would be greatly appreciated!

jacek
8th March 2006, 20:07
Try changing:
QMAKE_LIBS_X11 += -lkdeui -lkdecoreto
LIBS += -lkdeui -lkdecore -lcomedi -lrtaiRemember to rerun qmake to get a new Makefile.

zielchri
8th March 2006, 20:20
That gave me better results, but it isn't right yet. When I made that change I got the following:

smart-microsystem-lab:~/test # QTDIR=/usr/lib/qt3 make



g++ -o KDEMenu obj/KDEMenu.o obj/RT_DAQ.o obj/moc_KDEMenu.o -L/usr/lib/ -L/usr/lib/qt3/lib/ -L/usr/lib/ -L/usr/X11R6/lib/ -L/opt/kde3/lib -L/usr/lib -lkdeui -lkdecore -lcomedi -lrtai -lqt -lGLU -lGL -lXmu -lXext -lX11 -lm
/usr/lib/gcc-lib/i586-suse-linux/3.3.1/../../../../i586-suse-linux/bin/ld: cannot find -lrtai
collect2: ld returned 1 exit status
make: *** [KDEMenu] Error 1



So then I decided to get rid of -lrtai in that line just out of curiosity and got the following:

smart-microsystem-lab:~/test # qmake menu.pro -o Makefile
smart-microsystem-lab:~/test # QTDIR=/usr/lib/qt3 make



g++ -o KDEMenu obj/KDEMenu.o obj/RT_DAQ.o obj/moc_KDEMenu.o -L/usr/lib/ -L/usr/lib/qt3/lib/ -L/usr/lib/ -L/usr/X11R6/lib/ -L/opt/kde3/lib -L/usr/lib -lkdeui -lkdecore -lcomedi -lqt -lGLU -lGL -lXmu -lXext -lX11 -lm
obj/RT_DAQ.o(.text+0x26): In function `set_volts':
/root/test/RT_DAQ.c:61: undefined reference to `printk'
obj/RT_DAQ.o(.text+0x2b):/root/test/RT_DAQ.c:62: undefined reference to `rt_task_wait_period'
obj/RT_DAQ.o(.text+0x39):/root/test/RT_DAQ.c:102: undefined reference to `rt_task_wait_period'
obj/RT_DAQ.o(.text+0x5a):/root/test/RT_DAQ.c:92: undefined reference to `rt_get_cpu_time_ns'
obj/RT_DAQ.o(.text+0xe6):/root/test/RT_DAQ.c:94: undefined reference to `rt_sleep'
obj/RT_DAQ.o(.text+0x123):/root/test/RT_DAQ.c:96: undefined reference to `rt_get_time_ns'
obj/RT_DAQ.o(.text+0x141):/root/test/RT_DAQ.c:99: undefined reference to `rtf_put'
obj/RT_DAQ.o(.text+0x15c):/root/test/RT_DAQ.c:100: undefined reference to `rtf_put'
obj/RT_DAQ.o(.text+0x18e): In function `init_module':
/root/test/RT_DAQ.c:108: undefined reference to `printk'
obj/RT_DAQ.o(.text+0x193):/root/test/RT_DAQ.c:109: undefined reference to `rt_get_time'
obj/RT_DAQ.o(.text+0x1b5):/root/test/RT_DAQ.c:113: undefined reference to `rt_shm_alloc'
obj/RT_DAQ.o(.text+0x21d):/root/test/RT_DAQ.c:116: undefined reference to `rt_task_init'
obj/RT_DAQ.o(.text+0x254):/root/test/RT_DAQ.c:117: undefined reference to `rt_task_init'
obj/RT_DAQ.o(.text+0x268):/root/test/RT_DAQ.c:118: undefined reference to `rtf_create'
obj/RT_DAQ.o(.text+0x27c):/root/test/RT_DAQ.c:119: undefined reference to `rtf_create'
obj/RT_DAQ.o(.text+0x290):/root/test/RT_DAQ.c:120: undefined reference to `nano2count'
obj/RT_DAQ.o(.text+0x298):/root/test/RT_DAQ.c:120: undefined reference to `start_rt_timer'
obj/RT_DAQ.o(.text+0x2ce):/root/test/RT_DAQ.c:121: undefined reference to `rt_task_make_periodic'
obj/RT_DAQ.o(.text+0x30c): In function `cleanup_module':
/root/test/RT_DAQ.c:129: undefined reference to `stop_rt_timer'
obj/RT_DAQ.o(.text+0x318):/root/test/RT_DAQ.c:130: undefined reference to `rt_busy_sleep'
obj/RT_DAQ.o(.text+0x320):/root/test/RT_DAQ.c:131: undefined reference to `rt_task_delete'
obj/RT_DAQ.o(.text+0x32c):/root/test/RT_DAQ.c:132: undefined reference to `rt_shm_free'
obj/RT_DAQ.o(.text+0x338):/root/test/RT_DAQ.c:133: undefined reference to `rtf_destroy'
obj/RT_DAQ.o(.text+0x344):/root/test/RT_DAQ.c:134: undefined reference to `rtf_destroy'
obj/RT_DAQ.o(.text+0x34c):/root/test/RT_DAQ.c:135: undefined reference to `rt_task_delete'
collect2: ld returned 1 exit status
make: *** [KDEMenu] Error 1


Please let me know if you have any other ideas.

-Chris

jacek
8th March 2006, 21:06
OK, I've read a bit about this RTAI thing and it looks like you need two things:

a kernel module that will implement the real-time part of your application,
an user-space application that will serve as a front-end.
You can't link them together. Luckily RTAI provides some means of communication between the module and application. Maybe this guide (https://www.rtai.org/index.php?module=documents&JAS_DocumentManager_op=downloadFile&JAS_File_id=32) will be helpful.

zielchri
8th March 2006, 22:07
Thanks for the reply.

I've read through that document as well as many others, so maybe I need to clarify the issue a little further.

I can compile using a makefile a command based program using rtai and comedi by itself (with no qt involved). The makefile I use is below:



LINUXINC= /usr/src/linux/include
RTAIINC= /usr/realtime/include
COMEDIDIR= /devel/comedi-0.7.68/include
FLAGS=-g -D__KERNEL__ -DMODULE -O2
INCLD= -I$(LINUXINC) -I$(RTAIINC) -I/opt/kde3/include -I/usr/lib/qt3/include -I/usr/include -I$(QTDIR)/include
QT3LIB = /usr/lib/qt3/lib
QT3INC = /usr/lib/qt3/include

RT_DAQ:RT_DAQ.c RT_user
gcc -c $(FLAGS) $(INCLD) -I$(COMEDIDIR) RT_DAQ.c

RT_user:RT_user.cpp
g++ $(INCLD) -L$(QT3LIB) -I$(QT3INC) -I$(COMEDIDIR) -l comedi -O2 -o RT_user RT_user.cpp -lm -lqt


RT_user.cpp is the user space program and RT_DAQ.c is the kernel space program.

Okay, so it might be that I'm an electrical engineer and not a computer science major, but I thought I read that file as the RT_DAQ compiles in terms of RT_DAQ.c and RT_user, which is the program compiled in the lines below it.

I guess I always thought "RT_DAQ:RT_DAQ.c RT_user" was how the two files got linked together. Is this wrong?

If so, can I just use qmake with the suggestions already stated but leave out RT_DAQ.c in the .pro file because qmake won't connect the two together? That is, if I use qmake to generate RT_user, can I use another makefile I create myself (like the one above) to actually compile the kernel program with the RT_user compiled?

Sorry for my ignorance, but I hope that made sense. I'm thinking I can do this because the compiler doesn't appear to have any problems with the user space source code, just the kernel space program. Please let me know what you think.

-Chris

jacek
8th March 2006, 22:29
I guess I always thought "RT_DAQ:RT_DAQ.c RT_user" was how the two files got linked together. Is this wrong?
Yes, it is. That's only a rule that tells the make program that the "RT_DAQ" target depends on "RT_DAQ.c" and "RT_user" (i.e. it states that if one of them has been changed the RT_DAQ should be rebuilt).

Since you are building two separate things, you could use the subdir template:

Suppose your project directory has following layout:
./rt.pro
./frontend/rt_user.pro
./frontend/RT_user.cpp
./module/Makefile
./module/RT_DAQ.c

Where rt.pro is:
TEMPLATE = subdirs
SUBDIRS += frontend module

./frontend/rt_user.pro is:
TEMPLATE = app
TARGET = ../bin/rt_client
MOC_DIR = ../build
OBJECTS_DIR = ../build
INCLUDEPATH += /usr/src/linux/include \
/usr/realtime/include \
/devel/comedi-0.7.68/include \
/opt/kde3/include
LIBS += -L/opt/kde3/lib -lkdeui -lkdecore \
-L/devel/comedi-0.7.68/lib -lcomedi
SOURCES += RT_user.cpp

and ./module/Makefile is:
LINUXINC= /usr/src/linux/include
RTAIINC= /usr/realtime/include
COMEDIDIR= /devel/comedi-0.7.68/include
FLAGS=-g -D__KERNEL__ -DMODULE -O2
INCLD= -I$(LINUXINC) -I$(RTAIINC) -I/usr/include

RT_DAQ: RT_DAQ.c
gcc -c $(FLAGS) $(INCLD) -I$(COMEDIDIR) RT_DAQ.c

If all paths are correct and I haven't forgot anything it should build without any problems.

zielchri
8th March 2006, 22:54
Hey thanks for the reply. But can you tell me how I would go about compiling that? Would I start by using "qmake rt.pro -o Makefile" then move into the frontend directory and use "qmake rt_user.pro -o Makefile" then run the rt.pro makefile? Please let me know.

jacek
8th March 2006, 23:26
But can you tell me how I would go about compiling that?
It should be enough to run "qmake && make" in the directory where rt.pro is located (if it doesn't want to work, you will have to run qmake in the frontend directory too).

zielchri
9th March 2006, 00:09
Hey thanks guys, it works now!!!!

For anybody else interested or is having the same problem, the solution was to follow each suggestion listed above, as well as write a short script to copy the object file of the kernel program and the compiled program (above rt_client) into a seperate folder. There I also included a .runinfo file, which is necessary to load the real-time parts of rt_client (otherwise when I just ran ./rt_client no real-time sampling occured in my system). Once those three files were there I typed rtai-load at the command prompt (while in that folder) and the program ran just like it should! :)

jacek
9th March 2006, 00:11
as well as write a short script to copy the object file of the kernel program and the compiled program (above rt_client) into a seperate folder.
You can tweak above files to do the same automatically.