[CMake-Promote] request for proofreading

Alexander Neundorf a.neundorf-work at gmx.net
Wed Jan 11 17:30:56 EST 2006


Hi, 
 
I want to blog how to compile KDE3 software using cmake. But since I'm 
not used to writing longer texts in english, it would be nice if you 
could proofread it before and let me know if it's ok or if I should 
change some things. Is the spelling and grammar ok, is everything clear 
or are there logical gaps ? 
(I plan to write another article as documentation about the FindKDE3 
module, where the commands will be explained one by one). 
 
Here comes the text: 
 
 
-----8<---------------8<-------------8<-------------------- 
 
Using cmake for building KDE 3 software... 
 
some weeks ago I blogged how I managed to compile kpager using cmake. 
In the meantime the am2cmake script was a bit fine tuned and now even 
more works. 
You can get the script and the KDE 3 support files for cmake from here: 
http://websvn.kde.org/trunk/KDE/kdesdk/cmake/ 
So here we go: 
 
<b>How to build an application:</b> 
 
Checkout kpager and run the am2cmake script, this will produce a 
CMakeLists.txt. 
Just run "cmake ." in this directory, followed by make, and it will 
produce a working kpager binary without any manual tweaking. You can find 
more details about the generated CMakeLists.txt here:  
http://www.kdedevelopers.org/node/1668 
So let's proceed with something new... 
 
<b>How to build an KDE ioslave and a KPart:</b> 
 
Checkout kdebase/kioslave/man, the man-page ioslave. 
As before, run the am2cmake script and try to compile it. This time it 
won't work,  
it can't find config.h. This means, the man-ioslave needs a config.h with 
defines figured out by a configure script. kio_man contains ifdefs for 
HAVE_UNISTD_H and HAVE_STRING_H. Creating this file is the job of 
autoconf/configure when using the autotools. 
How to do this with cmake ? It's easy: 
 
<pre> 
INCLUDE(CheckIncludeFiles) 
 
CHECK_INCLUDE_FILES( unistd.h HAVE_UNISTD_H) 
CHECK_INCLUDE_FILES( string.h HAVE_STRING_H) 
 
CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/config.h.cmake 
${CMAKE_BINARY_DIR}/config.h) 
</pre> 
 
CheckIncludeFiles is a script file (in cmake language a <i>module</i>) 
which contains the function "CHECK_INCLUDE_FILES(filename 
outputVariable)". 
This function is called once to check for the existance of unistd.h and 
once for string.h, and the results are stored respectively on 
HAVE_UNISTD_H and HAVE_STRING_H. If they were found, they are set to "1", 
if not they are set to an invalid state. Finally the line 
CONFIGURE_FILE() creates a config.h from a config.h.cmake (similar as 
configure creates a config.h from a config.h.in). 
How does the config.h.cmake look? 
 
<pre> 
#ifndef CONFIG_H 
#define CONFIG_H 
 
#cmakedefine HAVE_UNISTD_H 
#cmakedefine HAVE_STRING_H 
 
#endif 
</pre> 
 
The CONFIGURE_FILE() command will read this file and replace  
"#cmakedefine HAVE_UNISTD_H" with "#define HAVE_UNISTD_H 1" if unistd.h 
was found, or "#undef HAVE_UNISTD_H" if not (and respectively for 
string.h). 
 
Now run make again and it should compile without problems. After "make 
install" as root you will have a cmake-compiled version of the 
man-ioslave on your system :-) 
This means, if everything was installed in the correct directory. By 
default cmake uses /usr/local as install prefix, just as the autotools 
do. To change this, start "ccmake ." (yes, double c make). This opens a 
ncurses "GUI" where you can adjust the cmake variables, among them 
CMAKE_INSTALL_PREFIX. Set this to the directory where your KDE is 
installed.<br> 
 
Ok, and now let's have a look at the generated CMakeLists.txt: 
 
<pre> 
FIND_PACKAGE(KDE3 REQUIRED) 
 
SET(CMAKE_VERBOSE_MAKEFILE ON) 
 
ADD_DEFINITIONS(${QT_DEFINITIONS} ${KDE3_DEFINITIONS}) 
 
LINK_DIRECTORIES(${KDE3_LIB_DIR}) 
 
INCLUDE_DIRECTORIES( ${KDE3_INCLUDE_DIR} ${QT_INCLUDE_DIR} 
${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}  ) 
</pre> 
 
The part upto here has changed slightly since the last version, now the 
FindKDE3.cmake module doesn't actively set the values, it justs sets the 
variables, which can then be used with ADD_DEFINITIONS(), 
INCLUDE_DIRECTORIES() and LINK_DIRECTORIES(). This is more conform to 
standard cmake-behaviour. 
 
<pre> 
INCLUDE(CheckIncludeFiles) # module for testing for headers coming with 
cmake 
 
CHECK_INCLUDE_FILES( unistd.h HAVE_UNISTD_H) 
CHECK_INCLUDE_FILES( string.h HAVE_STRING_H) 
 
CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/config.h.cmake 
${CMAKE_BINARY_DIR}/config.h) 
</pre> 
 
These lines were added manually, configure checks are not converted by 
am2cmake. 
 
<pre> 
########### next target ############### 
 
SET(kio_man_test_SRCS 
kio_man_test.cpp 
) 
 
KDE3_AUTOMOC(${kio_man_test_SRCS}) 
 
IF(KDE3_BUILD_TESTS) 
KDE3_ADD_EXECUTABLE(kio_man_test ${kio_man_test_SRCS}) 
 
TARGET_LINK_LIBRARIES(kio_man_test  ${QT_AND_KDECORE_LIBS} ) 
 
ENDIF(KDE3_BUILD_TESTS) 
 
########### next target ############### 
 
SET(man2html_SRCS 
dummy.cpp 
) 
 
KDE3_AUTOMOC(${man2html_SRCS}) 
 
FILE(WRITE dummy.cpp "//autogenerated file by cmake\n") 
IF(KDE3_BUILD_TESTS) 
KDE3_ADD_EXECUTABLE(man2html ${man2html_SRCS}) 
 
TARGET_LINK_LIBRARIES(man2html  ${QT_AND_KDECORE_LIBS} ) 
 
ENDIF(KDE3_BUILD_TESTS) 
</pre> 
 
This Makefile.am contained two test binaries, this is translated 
correctly to cmake. They will only be built if the cmake option 
"KDE3_BUILD_TESTS" is enabled. This can be done with ccmake. 
 
<pre> 
########### next target ############### 
 
SET(kio_man_PART_SRCS 
man2html.cpp 
kio_man.cpp 
) 
 
KDE3_AUTOMOC(${kio_man_PART_SRCS}) 
 
KDE3_ADD_KPART(kio_man ${kio_man_PART_SRCS}) 
 
TARGET_LINK_LIBRARIES(kio_man  ${QT_AND_KDECORE_LIBS} ) 
 
INSTALL_TARGETS(/lib/kde3 kio_man ) 
</pre> 
 
Here comes the actual man-ioslave. At first the source files are listed, 
then they are "automoced". The KDE3_ADD_KPART() creates the loadable 
plugin named kio_man.so. Maybe the name "KDE3_ADD_KPART" could be changed 
to something like "KDE3_ADD_PLUGIN" or something like that, not sure. 
Then INSTALL_TARGETS() creates the install rule for the target "kio_man", 
i.e. kio_man.so will be installed to ${CMAKE_INSTALL_PREFIX}/lib/kde3. 
What you can't see in this snippet, is that KDE3_ADD_KPART() also creates 
an appropriate .la file together with the accompanying install rule. 
AFAIK this is required for the dynamic loading by KDE. 
 
<pre> 
########### next target ############### 
 
SET(kmanpart_PART_SRCS 
kmanpart.cpp 
) 
 
KDE3_AUTOMOC(${kmanpart_PART_SRCS}) 
 
KDE3_ADD_KPART(kmanpart WITH_PREFIX ${kmanpart_PART_SRCS}) 
 
TARGET_LINK_LIBRARIES(kmanpart  ${QT_AND_KDECORE_LIBS} kparts ) 
 
INSTALL_TARGETS(/lib/kde3 kmanpart ) 
</pre> 
 
And the next target, this time a real KPart, which can be used to view 
man-pages directly within konqueror (i.e. not via the man-ioslave). As 
you can see here KDE3_ADD_KPART() is called with the special parameter 
"WITH_PREFIX", which has the effect that the resulting file will be named 
"libkmanpart.so", just as it was in the original Makefile.am The rest is 
basically the same, additionally it links to libkparts. 
 
 
<pre> 
########### install files ############### 
 
INSTALL_FILES( /share/apps/kio_man FILES kio_man.css ) 
INSTALL_FILES( /share/services FILES man.protocol kmanpart.desktop ) 
 
KDE3_PLACEHOLDER() 
</pre> 
 
And here you can see the autmatically converted install rules for the 
remaining files.<br> 
IMO this is definitely more obvious than the syntax we had in the 
Makefile.am's. 
Compare e.g. the lines above to the following lines from the Makefile.am: 
<pre> 
kdelnk_DATA = man.protocol kmanpart.desktop 
kdelnkdir = $(kde_servicesdir) 
</pre> 
 
Do these two lines tell you what they do ?  
As Matthias puts it: "An API is intuitive [...] if a programmer who 
doesn't know the API can understand code written using it." 
 
 
<b>How to build a KDEInit-enabled application</b> 
 
Now let's try to build another application, kcalc.  
Check it out, run am2cmake, cmake and make. It will fail. Again, a 
config.h is missing, so we have to add the required configure checks: 
 
<pre> 
INCLUDE(CheckIncludeFiles)   
 
CHECK_INCLUDE_FILES( unistd.h HAVE_UNISTD_H) 
CHECK_INCLUDE_FILES( string.h HAVE_STRING_H) 
CHECK_INCLUDE_FILES( ieeefp.h HAVE_IEEEFP_H) 
 
INCLUDE(CheckFunctionExists)  
 
CHECK_FUNCTION_EXISTS( isinf HAVE_FUNC_ISINF) 
 
CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/config.h.cmake 
${CMAKE_BINARY_DIR}/config.h) 
</pre> 
 
You know already most of it from the man-ioslave. Additionally here a 
test for the function isinf() was required, this is done similar to the 
header check using the CHECK_FUNCTION_EXIST() function. I guess you 
already know how config.h.cmake looks now: 
<pre> 
#ifndef CONFIG_H 
#define CONFIG_H 
 
#cmakedefine HAVE_UNISTD_H 
#cmakedefine HAVE_STRING_H 
#cmakedefine HAVE_FUNC_ISINF 
 
#endif 
</pre> 
 
But it still won't compile, some include directories have to be added and 
some libs to link to. Once this is done, it compiles cleanly. Here 
kcalc/CMakeLists.txt: 
 
<pre> 
FIND_PACKAGE(KDE3 REQUIRED) 
 
SET(CMAKE_VERBOSE_MAKEFILE ON) 
 
ADD_DEFINITIONS(${QT_DEFINITIONS} ${KDE3_DEFINITIONS}) 
 
LINK_DIRECTORIES(${KDE3_LIB_DIR}) 
 
ADD_SUBDIRECTORY( knumber ) 
 
INCLUDE_DIRECTORIES( ${KDE3_INCLUDE_DIR} ${QT_INCLUDE_DIR} 
${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}  ) 
 
INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR}/knumber ) # added 
manually 
</pre> 
 
Nothing fancy up to here, the above line had to be added manually, and 
the 
configure checks below too. 
 
<pre> 
# configure checks, added manually 
 
INCLUDE(CheckIncludeFiles)  #module to test for headers, coming with 
cmake 
 
CHECK_INCLUDE_FILES( unistd.h HAVE_UNISTD_H) 
CHECK_INCLUDE_FILES( string.h HAVE_STRING_H) 
CHECK_INCLUDE_FILES( ieeefp.h HAVE_IEEEFP_H) 
 
INCLUDE(CheckFunctionExists) #module to test for existence of functions, 
coming with cmake 
 
CHECK_FUNCTION_EXISTS( isinf HAVE_FUNC_ISINF) 
 
CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/config.h.cmake 
${CMAKE_BINARY_DIR}/config.h) 
</pre> 
 
Now comes the first target, kcalc as a KDEInit Loadable Module, short KLM 
(i.e.an application which can be started by forking from kdeinit) 
 
<pre> 
 
########### next target ############### 
 
SET(kcalc_KDEINIT_SRCS 
kcalc.cpp 
kcalc_button.cpp 
kcalc_const_button.cpp 
kcalc_const_menu.cpp 
kcalc_core.cpp 
kcalcdisplay.cpp 
dlabel.cpp 
stats.cpp 
) 
 
KDE3_AUTOMOC(${kcalc_KDEINIT_SRCS}) 
 
SET( kcalc_UI 
colors.ui 
general.ui 
constants.ui 
) 
 
KDE3_ADD_UI_FILES(kcalc_KDEINIT_SRCS ${kcalc_UI} ) 
 
SET( kcalc_KCFG_SRCS 
kcalc_settings.kcfgc 
) 
 
KDE3_ADD_KCFG_FILES(kcalc_KDEINIT_SRCS ${kcalc_KCFG_SRCS}) 
 
KDE3_ADD_KLM( kcalc ${kcalc_KDEINIT_SRCS}) 
 
# gmp, knumber and kdeui added manually 
TARGET_LINK_LIBRARIES(kdeinit_kcalc  ${QT_AND_KDECORE_LIBS} kdeui knumber 
gmp) 
INSTALL_TARGETS(/lib kdeinit_kcalc ) 
 
TARGET_LINK_LIBRARIES( kcalc kdeinit_kcalc ) 
INSTALL_TARGETS(/bin kcalc ) 
</pre> 
 
Here is some new stuff. kcalc uses some designer ui files. These are 
added to the target using KDE3_ADD_UI_FILES(). kcalc also uses 
kconfig_compiler. The kcfgc file is processed using 
KDE3_ADD_KCFGC_FILES(). Finally the KLM is created using KDE3_ADD_KLM(). 
This command creates both a KDE loadable module and a normal executable. 
Notable is the command TARGET_LINK_LIBRARIES(). am2cmake didn't recognize 
that kcalc links to libkdeui.so, libgmp.so and the static library 
libknumber.a. As you can see it is enough to specify the actual  library 
name, i.e. "knumber" in the link command. This is enough for cmake, since 
libknumber.a is part of this project, cmake knows where to find and how 
to link to it. 
The other lines are basically only install instructions. 
 
<pre> 
 
 
########### install files ############### 
 
INSTALL_FILES( /share/applications/kde FILES kcalc.desktop ) 
INSTALL_FILES(  /share/config.kcfg FILES kcalc.kcfg ) 
INSTALL_FILES( /share/apps/kcalc FILES kcalcui.rc ) 
INSTALL_FILES( /share/apps/kconf_update FILES kcalcrc.upd ) 
 
KDE3_INSTALL_ICONS( hicolor ) 
</pre> 
 
 
And now a short look at kcalc/knumber/CMakeLists.txt: 
 
<pre> 
ADD_SUBDIRECTORY( tests ) 
 
INCLUDE_DIRECTORIES( ${KDE3_INCLUDE_DIR} ${QT_INCLUDE_DIR} 
${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) 
 
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/.. ) # added manually 
 
ADD_DEFINITIONS(-D_GNU_SOURCE -D_ISOC99_SOURCE ) # added manually 
 
########### next target ############### 
 
SET(knumber_STAT_SRCS 
knumber.cpp 
knumber_priv.cpp 
) 
 
KDE3_AUTOMOC(${knumber_STAT_SRCS}) 
 
ADD_LIBRARY(knumber STATIC ${knumber_STAT_SRCS}) 
 
 
########### install files ############### 
 
 
KDE3_PLACEHOLDER() 
</pre> 
 
Nothing very exciting here. Here a static library is built (the "STATIC" 
keyword in the ADD_LIBRARY() command). The two lines marked as such had 
to be added manually. 
 

-- 
Telefonieren Sie schon oder sparen Sie noch?
NEU: GMX Phone_Flat http://www.gmx.net/de/go/telefonie


More information about the CMake-Promote mailing list