Use the Imakefile! or: Some mean tricks to get the stuff compiled! Traditionally X apps come with an Imakefile to use the old tool available for virtually all official X11R6 platforms (and some others). Its use is recommended in the FAQ. A) A short introduction ---------------------- (by Hung-Chi Chu) Autoconf vs. Imakefile ====================== I would like to share my experience about autoconf and Imakefile. - autoconf/emx is not perfect, especially on Makefiles generated automatically. I don't like to modify any auto-generated files since they are "monsters" and the modification will be overwritten when the next configure runs. - autoconf/emx is nearly perfect for generating config.h except that occasionally I need to add/modify a few lines in configure.in for searching some special functions in add-on libraries. - for other auto-generated and non-intermediate files which have path definition in them, such as the script 'gtk-config', write a new file called *.os2 by substitute the drive letter with ${X11ROOT} et al. - Imakefile is neat for X/2 libraries and programs. It is analogous to "Makefile.am" for autoconf. It is not difficult to write an Imakefile from Makefile.am. For non-X lib/prog, it is also simple to rewrite a neat Makefile for os2 (ex. Makefile.emx) from Makefile.am. - The effort of rewriting Imakefile/Makefile.emx is almost at finding all DEFINES for gcc. This can be easily done by searching "-D" in Makefiles generated by configure. - Following are the main steps I apply to do port: 1. use autoconf/emx to generate config.h, Makefile et al. 2. for the first version: 2.1 rewrite Imakefile/Makefile.emx from Makefile.am 2.2 check some auto-generated and non-intermediate files. modify and rename them as *.os2 if necessary 2.3 for dynamic library, make a module definition file *.def and a response file *os2.rsp (necessary for Imakefile) 3. for the following versions: 3.1 apply the patch of the previous version 3.2 diff -u previous_version/Makefile.am this_version/Makefile.am 3.3 modify Imakefile/Makefile.am from the result of 3.1 3.4 "diff -u" of any other special *.in files and modify the corresponding *.os2 3.5 for dynamic libraries, check *.def and modify it if necessary 4. for Imakefile: xmkmf; make Makefiles; make or xmkmf -a; make for Makefile.emx: gmake -f Makefile.emx all 5. "make install" and make a patch file by "diff -ruN" if all work well 6. make the zip package. :-) - I have used these procedures to port many libs/progs, including some not-yet-released GNOME-related binaries. :-) B) Preliminary steps -------------------- The following is meant to overcome some simple, nevertheless annoying problems and to make things work faster: Quick and simple fixes, some dirty stolen tricks. 1) RTF docs ----------- - Read the README file! - Read the INSTALL file! - Read any additional info files from the program authors. Many problems ocurring under special UN*X flavours have a similar counterpart on OS/2 (others haven't, but this shall be a simple guide :-) 2) Some additions to /XFree86/lib/X11/config/os2.cf and os2.rules ----------------------------------------------------------------- a) I tried to make life easier, so I've added some defines to the vendor specific imake template file: /XFree86/lib/X11/config/os2.cf. Reasons for that: - Never edit generated Makefiles by hand: Far too much work for larger projects and errors are to be expected. (But sometimes unavoidable). - If things work and don't break other projects, they should be mailed to the respective lists in order to finally become standard. - Read the /XFree86/lib/X11/config/README file. The following excerpt may be useful, too: My proposed changes of /XFree86/lib/X11/config/os2.cf: #define ManSuffix 1x #define LibManSuffix 3x #define FileManSuffix 4x instead of #define ManSuffix 1 [... etc.] (This helps a lot, if you already installed or will install many man pages. I'm sure this will happen!! Also this is for good reasons now standard on most recent UN*X versions.) Change #define CplusplusCmd g++ to #define CplusplusCmd gcc #define CplusplusOptions -D__ST_MT_ERRNO__ -Zmtd -Zsysv-signals -O2 (I can't find any reason to call emx gcc by a different name for C++ or to use different options here. But there were reports of problems with the experimental compilers 'pgcc' aka 'egcs'; you might want to omit -O2 therefore!) Change #define ExtraLibraries -lsocket -lbsd to XCOMM (There is now a standard -lz port available on Hobbes) #define HasZlib YES #define GzipLibrary -lz #define ExtraLibraries -lsocket -lbsd -lwrap (Shouldn't do any harm, but make smaller executables with OS/2 API calls.) Imake.tmpl provides defaults for the following variables: HasZlib boolean for system has libz b) EMX docs recommend using object module format (-Zomf; link386.exe) for better stability, if neither gdb.exe nor fork() shall be used. The following additions to /XFree86/lib/X11/config/os2.rules are meant to facilitate the switch in this case; nevertheless you'll have to check dependency lines and rules, if a.out format is still used (and some rules for libraries will become obsolete, but not harmful): XCOMM $XConsortium: os2.rules /main/1 1996/10/31 14:47:27 kaleb $ XCOMM platform: $XFree86: xc/config/cf/os2.rules,v 3.15 1997/01/05 11:49:39 dawes Exp $ .SUFFIXES: .a .lib .o .obj .c .C .cc .cpp .c.$O: $(CC) $(CFLAGS) -c $*.c #if HasCplusplus .$C.$O: $(CXX) $(CFLAGS) -c $*.$C #endif XCOMM Uncomment if using OMF (emxomf called automatically by gcc)! XCOMM CC = gcc -Zomf XCOMM O = obj XCOMM LD = emxomfld C = C XCOMM or .cpp O = o A = .a C) Common initial problems -------------------------- Initially I thought imake was a labyrinthic beast, deserving the title of the Minotaurus among the make tools. But with small and simple fixes to work around some annoying bugs I was able to tame it a bit, so that 'xmkmf' at least does something useful: 1) 'xmkmf -a' crashes because of 'sh' and 'Rexx' conflicts ---------------------------------------------------------- Usually Imakefiles silently assume they are running on UNIX in a Bourne 'sh' environment, since authors intentionally do not support non UNIX platforms. Just try running the following changed Rexx scripts first, to create a working environment: make.cmd /* REXX */ '@echo off' PARSE ARG a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 /* x11make.exe 'MAKE=x11make.exe SHELL=d:/os2/cmd.exe' a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 */ 'SET SHELL=D:\OS2\CMD.EXE' 'SET X11SHELL=D:\OS2\CMD.EXE' 'set emxshell=D:\OS2\CMD.EXE' 'set CONFIG_SHELL=D:\OS2\CMD.EXE' 'set MAKE_SHELL=D:\OS2\CMD.EXE' x11make.exe 'MAKE=x11make.exe SHELL= MAKE_SHELL=d:\os2\cmd.exe CONFIG_SHELL=d:\os2\cmd.exe' a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 or gmake.cmd /* REXX */ '@echo off' PARSE ARG a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 'set SHELL=d:/bin/ash.exe' 'SET X11SHELL=D:\OS2\CMD.EXE' 'set emxshell=d:/bin/ash.exe' 'set MAKE_SHELL=d:/bin/ash.exe' /* x11make.exe 'MAKE=x11make.exe SHELL=' a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 */ x11make.exe 'MAKE=x11make.exe SHELL=d:/bin/ash.exe MAKE_SHELL=d:/bin/ash.exe CONFIG_SHELL=d:/bin/ash.exe' a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 ================================== Normally, running make.cmd should be sufficient, since the current OS/2 implementation by H. Veit and others makes extensive use of Rexx, needs cmd.exe as command processor and is incompatible with Bourne shells. Here a number of problems arise with many common Imakefiles. Now lets assume xmkmf worked. Theoretically the steps are: xmkmf make Makefiles make depend make all (or simply: make) .\programname.exe for testing make install make install.man 2) 'make' crashes because of 'sh' and 'Rexx' conflicts ------------------------------------------------------ Imake is misconfigured on most (commercial) UN*X platforms. Authors normally compensate this by including many lines of (normally highly complicated) Bourne shell code and calling several Bourne shell scripts in the Imakefile. In this case 'make' won't work. Nor does a sh.exe as make shell work: The current implementation depends on cmd.exe and Rexx. Finding and rewriting everything in those immense Imakefiles, helper scripts and Makefiles isn't really an alternative. Just try alternatively make and gmake (having installed e.g. /bin/ash.exe). Now make should simply resume where it has crashed. Just delete 'products' of those crashes (empty script output, truncated object files, core dumps, etc.) before resuming the process. This makes using Imake real fun! 3) Imakefile examples --------------------- $XFree86: config/README states: "The easiest way to write an Imakefile is to find another one that does something similar and copy/modify it!" Here some strongly shortened examples that use Bourne shell code: sh -c 'for i in '"$(TEXT) $(SRCS) $(MISC) $(HDRS)"' ; do... etc., etc. a) creating a library: NormalLibraryTarget(rw, $(OBJS)) -------------------------- # Imakefile for xpaint read/write directory #include "../version" #include "../Local.config" INCLUDES = -I.. $(XPM_INCLUDE) $(TIFF_INCLUDE) $(JPEG_INCLUDE) $(PNG_INCLUDE) # Nothing to change below here TIFF_SRC = writeTIFF.c readTIFF.c #ifdef HaveTIFF TIFF_OBJ = writeTIFF.$O readTIFF.$O TIFF_DEF = -DHAVE_TIFF #endif [...] XPM_SRC = readWriteXPM.c XPM_OBJ = readWriteXPM.$O SGI_SRC = readWriteSGI.c #ifdef SGIArchitecture SGI_OBJ = readWriteSGI.$O SGI_DEF = -DHAVE_SGI #endif DEFINES = $(XPM_DEF) $(TIFF_DEF) $(SGI_DEF) $(JPEG_DEF) $(PNG_DEF) \ SRCS = rwTable.c \ readWriteXBM.c readWritePNM.c readWriteXWD.c writePS.c \ readGIF.c writeGIF.c $(XPM_SRC) $(TIFF_SRC) $(SGI_SRC) \ $(JPEG_SRC) $(PNG_SRC) libpnmrw.c OBJS = rwTable.$O \ readWriteXBM.$O readWritePNM.$O readWriteXWD.$O writePS.$O \ readGIF.$O writeGIF.$O $(XPM_OBJ) $(TIFF_OBJ) $(SGI_OBJ) \ $(JPEG_OBJ) $(PNG_OBJ) libpnmrw.$O HDRS = libpnmrw.h rwTable.h MISC = Imakefile NormalLibraryTarget(rw, $(OBJS)) makelist: sh -c 'for i in '"$(TEXT) $(SRCS) $(MISC) $(HDRS)"' ; do \ echo $(CURRENT_DIR)/$$i >> ../filelist ; done ' rwTable.$O: ../Local.config ---------------------------- b) creating an executable: ComplexProgramTarget(xart) ------------------------------------ #include "./version" #include "./Local.config" DEFINES = $(ARCH_DEFINES) $(EXTRA_DEFINES) $(XPM_INCLUDE) \ -DXPAINT_VERSION=\"$(VERSION)\" # Nothing to change below here ## unless you've added a file, like e.g. a brush bitmap XPSRC = [...] [...] SRCS = $(XPSRC) $(OPSRC) $(XPWIDSRC) OBJS = $(XPOBJ) $(OPOBJ) $(XPWIDOBJ) HDRS = [...] [...] SYS_LIBRARIES = XawClientLibs -lm #ifdef SGIArchitecture SGI_LIB = -limage #endif DEPLIBS = always xart.man xart.ad LOCAL_LIBRARIES = LibraryTargetName(rw/librw.a) $(XPM_LIB) $(TIFF_LIB) $(SGI_LIB) $(JPEG_LIB) $(PNG_LIB) SUBDIRS = rw ComplexProgramTarget(xart) InstallAppDefaults(XArt) NamedMakeSubdirs(always, $(SUBDIRS)) MakefileSubdirs($(SUBDIRS) bitmaps Doc) CleanSubdirs($(SUBDIRS)) # Other targets... clean:: rm -f xart.ad.h DefaultRC.txt.h Help.txt.h PGP.* xart.man xart.ad includes:: xart.ad.h DefaultRC.txt.h Help.txt.h xart.man: xart.man.in version sed -e 'sáXPAINT_VERSIONá$(VERSION)á' < xart.man.in > $@ Colormap.$O: ColormapP.h Colormap.h [...] makelist:: -$(RM) filelist @touch filelist makelist:: sh -c 'for i in '"$(TEXT) $(SRCS) $(MISC) $(HDRS)"' ; \ do echo $(CURRENT_DIR)/$$i >> $(TOP)/filelist ; done ' NamedTargetSubdirs(makelist, $(SUBDIRS) bitmaps Doc, , , makelist) kit: makelist sh -c 'sum="`cat filelist`" ; makekit -oMANIFEST MANIFEST $$sum' tar: makelist sh -c 'cd .. ; rm -f xpaint-$(VERSION).tar.gz; \ tar czf xpaint-$(VERSION).tar.gz \ `sed -e "s:^\./::" -e "s:^:xpaint/:" xpaint/filelist`' TAGS: $(SRCS) $(HDRS) $(RWSRC) etags -t -o ./TAGS $(XPSRC) $(OPSRC) $(XPWIDSRC) $(RWSRC) $(HDRS) certification: makelist -$(RM) $(CERTIFICATION) certify `cat filelist` ---------------------------------------- c) Some maybe useful (or useless) defines: You may want to add parts of it to your Imakefile (or Local.config, etc.) in case of problems. Use comments, else you'll forget about these hackish def's!! Beware: Redefines of functions are debugging headaches: The actual code won't be explicitly in the sources; you will forget, that you redef'd! Awful coding style!! #ifdef OS2Architecture XCOMM XCOMM #define StrcasecmpDefines -DNEED_STRCASECMP -Dstrcasecmp=stricmp\ XCOMM XCOMM -Dstrncasecmp=strnicmp -Dstrcmp=stricmp XCOMM XCOMM #include /* OS/2 does not have everything */ XCOMM XCOMM #define lstat stat XCOMM XCOMM #define S_ISLNK() false XCOMM XCOMM #define S_ISBLK() false XCOMM XCOMM #define symlink() (0) XCOMM XCOMM #define readlink(s,t,l) (strcpy(t,s),strlen(t)) XCOMM XCOMM /* drive letter support needs major rewriting XCOMM XCOMM * #define getcwd _getcwd2 XCOMM XCOMM * #define chdir _chdir2 */ XCOMM XCOMM #define strcasecmp stricmp XCOMM XCOMM #define strcmp stricmp ARCH_DEFINES = -DSTDC_HEADERS=1 -DHAVE_STRING_H=1 -DHAVE_STDLIB_H=1\ -DHAVE_PARAM_H=1 -DHAVE_MEMORY_H=1 -DHAVE_ALLOCA_H=1 -DHAVE_ALLOCA=1\ -DHAVE_STRERROR=1 -Dlstat=stat -DS_ISLNK=false -DS_ISBLK=false -Dsymlink()=(0)\ -Dreadlink(s,t,l)=(strcpy(t,s),strlen(t) -D__STDC__ -Dstrcasecmp=stricmp\ -Dstrncasecmp=strnicmp #endif