A couple of HOWTOs that got into life during the project.
Propositions, corrections and comments please to: Linus Gasser.
ZOPE
Zope-Handling
Installation
Installation of Zope is pretty straightforward and should be possible with the documentation at their website. One useful thing is to add the option
-P80
to the start-file of Zope, so as to set it to the standard html-port. Of course this means disabling a possibly present Apache.
If you want to get along with an installed apache, you have to put something like
<VirtualHost 128.178.8.77> ServerName lcmpc10.epfl.ch RewriteEngine On RewriteRule ^/cgi-bin - [L] RewriteRule ^/(.*) http://localhost:8080/VirtualHostBase/http/lcmpc10.epfl.ch:80/$1] [P] </VirtualHost>
In your /etc/httpd/conf/httpd.conf-file and then restart Apache with ‘service apache restart’. If you are on a Debian-system (lucky you), the file is called /etc/apache/httpd.conf and the port-number is 9673 instead of 8080. (Debian is superior in updating the packages. In order to get from RH 7.2 to RH 7.3, you need to reboot, not so in Debian. The transition from 2.2 to 3.0 has been done w/o reboot!) Furthermore you have to put a VirtualHostMonster in the root-direcotry of your Zope. Like this it should work. The long line above makes the link between the link the user sees and what Zope uses internally. If you fiddle around with it, you can even get different zones on the same server…
The other RewriteRule let’s a request on /cgi-bin going through unchanged. This is needed if you have scripts running in /cgi-bin that have nothing to do with Zope. If you want to have other directories that don’t run with Zope, you can insert entries just above the long line. The [L] means ‘last’, so if the apache-server encounters a request for /cgi-bin, it stops rewriting and serves this link.
Edit Page
One of the many advantages of zope is it’s capability to offer a direct editing of all the sources of a given web-page. So, as the site grows, you don’t have to bother about ftp, scp, xemacs, vi or any other of these things. All you have to do is to point your browser to the page you want to edit, then to add “/manage” to the current url. For this page this would be something like:
http://lcmpc10.epfl.ch/Menu/Menu2/How2/manage
Once you press return, you’re asked for a username and a password (which you may get by sending a nice e-mail to Linus Gasser) and then you can directly edit the file. In fact, this documentation itself is written using this method! Once you finished changing the file, don’t forget using the button “Save Changes”, then click on the tab “View” on top of the screen, and you see if you did good or bad in editing a source.
Makefile
Makefiles
This is a short introduction into Makefiles. For further information, you may go and have a good look at ‘info make’. It will tell you lots of things. This HowTo is wrapped around the Etrans-project and thus explains the Makefiles used therein. The directory-structure of Etrans is as follows:
Etrans-+-Frontend +-Radio-+-BTS +-MS
There is source-code that has to be compiled in the Frontend, BTS and MS directory. In all these three directories, there is also something to install. I chose to have four Makefiles all in all. One in the Etrans directory and one in each Frontend, BTS and MS respectively. The Makefile in the Etrans directory calls the other three with the appropriate action to take. I also took care to prepare everything for an easy installation into an rpm-package.
Etrans
This is the main-Makefile that may be called using some simple arguments:
- all
- (re)make all
- clean
- delete everything computer-generated
- install
- put the compiled binaries in the appropriate directories
The environment-variable RPM_BUILD_ROOT is taken as a possible base-dir for installation. If it is set for example to /tmp/install all files will go into /tmp/install/opt/radio. This is very useful when building rpm-packages.
Variable initialisation
# The directories where we have things to do SDIRS = Frontend Radio/MS Radio/BTS # The base-directory for installation RADIODIR = /opt/radio # Additionaly, we take care about a variable called # RPM_BUILD_ROOT, which is used when the source is packaged # into an rpm. INSTALLDIR = $(RPM_BUILD_ROOT)$(RADIODIR) # This variable is propagated to all lower Makefiles MAKEFLAGS += RADIODIR=$(RADIODIR) INSTALLDIR=$(INSTALLDIR)
You can see here how variables are defined in a Makefile. The only variable that is a bit special is MAKEFLAGS. Whenever one calls a Makefile in another directory, all variables in the MAKEFLAG are set for the other Makefile. So, if this Makefile callse Frontend/Makefile, in Frontend/Makefile it is possible to use RADIODIR as well as INSTALLDIR.
Rules
# Default rule. Only depends on rtl_O.mk all: Radio/rtl_O.mk @for a in $(SDIRS); do \ $(MAKE) -C $$a; \ done
This is the first rule. Also called a target. As it is the first one encountered in the Makefile, it is the default. So if you call ‘make’ without any arguments, this rule is called.
The ampersand in front of the ‘for’ command makes it invisible to the user. This is a bash-command and executes everything between ‘do’ and ‘done’ for all arguments given after ‘in’. In our example this is ‘Frontend’ ‘Radio/MS’ and ‘Radio/BTS’. It is good practice to use $(MAKE) instead of a simple ‘make’. The former ensures that important switches are given to the other Makefiles, too. Using the ‘-C’ switch, it is possible to call Makefiles from other directories. Where in a normal shell-command one would use ‘$a’, the ‘$’ has to be escaped, which is done in a Makefile by using two ‘$’.
# Clean current and lower directories clean: @for a in $(SDIRS); do \ $(MAKE) -C $$a clean; \ done
The only change is that this time we give an argument to the other Makefiles, so that all source-dirs are cleaned of computer-generated garbage.
# Install in the desired directories install: all # first off, call all other Makefiles recursively @for a in $(SDIRS); do \ $(MAKE) -C $$a install; \ done # if we're installing for an rpm, we have to create the dirs ifneq ($(RPM_BUILD_ROOT),) install -d $(RPM_BUILD_ROOT)/etc/profile.d endif # then install the scripts that take care of the env.-vars install -m 755 radio.sh radio.csh $(RPM_BUILD_ROOT)/etc/profile.d/ @echo setenv RADIO $(RADIODIR) >> $(RPM_BUILD_ROOT)/etc/profile.d/radio.csh @echo "[ -z \"\$$RADIO\" ] && RADIO=\"$(RADIODIR)\"" >> \ $(RPM_BUILD_ROOT)/etc/profile.d/radio.sh @echo export RADIO >> $(RPM_BUILD_ROOT)/etc/profile.d/radio.sh # and, copy the files needed for the FPGAs install -d $(INSTALLDIR)/rbt $(RPM_BUILD_ROOT)/dev install -m 444 rbt/* $(INSTALLDIR)/rbt # of course the start-scripts also need their place: install -m 755 Scripts/* $(INSTALLDIR)/bin # IMPORTANT: Install daq-node test -e $(RPM_BUILD_ROOT)/dev/daq0 || mknod $(RPM_BUILD_ROOT)/dev/daq0 c 127 0
The first part is the description of the rule ‘install’, as usual, we call all underlying Makefiles with the argument ‘install’. They then put the corresponding binary-files in the right directories.
When installing with the ‘install’ command, it is important to have the directories in place, if not ‘install’ quits with an error. As we want to install some files in /etc/profile.d, we have to create this directory in the case of an RPM-build (remember: an install during RPM-build is done in an empty directory). The ‘ifneq’ construct compares the RPM_BUILD_ROOT variable against an empty string.
The installation of the PATH is most easily done with two files in /etc/profile.d When bash or csh starts up, it searches all files in this directory and executes them one by one. bash takes *.sh and csh takes *.csh So all we have to do is put a radio.sh and a radio.csh that add the /opt/radio/bin directory to the path and also insert the RADIO environment variable that is used by the ‘startup’ file. All this is done using bash-functions and is pretty straightforward.
Last but not least we check for the /dev/daq0 link that is needed by the software radio in order to function correctly.
# a simple # rm -rf $(INSTALLDIR) # might do the trick. But what if somebody puts RADIODIR to # / ? As this would pretty bad, we delete more hardly uninstall: @for a in $(SDIRS); do \ $(MAKE) -C $$a uninstall; \ done rm -rf $(INSTALLDIR)/rbt rm -f $(INSTALLDIR)/bin/{Start*,stop} # This should protect eventual similar files rm -f $(RPM_BUILD_ROOT)/etc/profile.d/radio.*sh # removes radio/lib radio/bin radio rmdir $(INSTALLDIR)/{lib,bin,} || echo "failed on rmdir" rm -f $(RPM_BUILD_ROOT)/dev/daq0
Whenever you want to get rid of the software radio, you may do so by calling ‘make uninstall’, and everything is deleted. I use this sometimes to look if the rpms install correctly…
Radio/rtl_O.mk: /usr/rtlinux-3.1/rtl.mk @sed -e "s/-O2/-O/" /usr/rtlinux-3.1/rtl.mk > Radio/rtl_O.mk
There is a special file provided by rtlinux, called rtl.mk It’s to be included in the Makefile and sets the include-path to work with rtlinux. Unfortunatly it also sets an optimisation level of 2, which is too high for the code of the software-radio. This is why the ‘-O2’ is replaced by ‘-O’, and the rtl.mk file is written to rtl_O.mk in our local directory.
Frontend
The Frontend-Makefile is quite simple, no bad tricks are done. Let’s have a look at it:
Implicit rules
CFLAGS = -I/usr/rtlinux/linux -I/usr/rtlinux/include \ -I/usr/X11R6/include -I../Radio/DAQ/ -I../Radio/L1_DSP \ -I. -I/usr/include LDFLAGS = -lforms -lX11 -lm -lXpm -L/usr/X11R6/lib CC = kgcc -g
These are some standard definitions of the options to pass to the C-compiler. In this Makefile we make use of some ‘implicit rules’, that is, some things that are common to all compilation of every C-file. In fact, when you tell the make-program to get a file.o, it will automatically search for file.c and then do:
$(CC) $(CFLAGS) file.c -o file.o
Variables and substitutions
SOURCES = mainForm.c showChannel.c showSignal.c callbacks.c showText.c inputs.c OBJ = $(SOURCES:.c=.o)
This is my way to do it. First I define the variable SOURCES as all the .c-files I have in the Frontend-directory. I could’ve also written SOURCES = *.c, but if there would be some test.c, this would also be incorporated. The next line, OBJ = $(SOURCES:.c=.o) tells make to replace every occurance of “.c” in SOURCES with “.o”. Like this we don’t have to re-write the OBJ-line.
Rules
all: make.dep $(OBJ) sradio.o startup
Here we have a first rule. As it is the first one encountered in the Makefile, it is also the default one. That is, when you type “make” without parameters, this is what is called. The target “all” depends on 4 prerequisites: “make.dep”, “$(OBJ)”, “sradio.o” and “startup”. If any one of these is out-dated, it will be redone.
Dependencies
dep make.dep: $(CC) -MM $(SOURCES) $(CFLAGS) > make.dep
Another rule. This time for two targets: “make.dep” AND for “dep”. There are no prerequisites given, as it is supposed to be called only on user’s request. The line after make.dep: has to begin with a TAB-character. All lines beginning with a TAB-character are executed in the shell by “make”. So this actually calls the compiler and tells him to re-create a dependency-file. If you call “make dep”, it will re-create the dependency-file. This file holds all the dependencies of the source-files of the project. It is in the form
mainForm.o: mainForm.c /usr/include/forms.h mainForm.h showChannel.o: showChannel.c /usr/include/forms.h sradio.h mainForm.h \ showChannel.h [...]
It is pretty useful as it allows the makefile to know what files have to be recompiled when something changed. It states for example that whenever mainForm.c changes, it has to re-create mainForm.o which is in an implicit rule and will be done like described further up.
Including files
The dependency-file changes over time. This is why it isn’t written directly in the Makefile. Instead we “include” it. There is one caveat, though: after a “make clean”, the make.dep file isn’t available, and “make” will tell you so. This is not hindering compilation, but not nice. So, there is a simple line to help that:
ifeq (make.dep, $(wildcard make.dep)) include make.dep endif
“ifeq” means “if equal”. It takes two parameters that it searches for equality. The first one is the name make.dep (not the file), while the second one searches for all files called “make.dep” and returns them. So if the $(wildcard…) doesn’t find anything, it returns zero, the equality doesn’t hold and the line “include make.dep” isn’t executed. This is a bit more nice.
Special cases
Always when there are some default rules, they won’t fit all. Also in this small project, a couple of files need special treatment:
sradio.o: sradio.c $(CC) $(CFLAGS) -DLINUX -DUSER -Wall -O2 -c sradio.c
“sradio.c” includes some system-specific files that need extra definitions and special optimisation.
startup: $(OBJ) startup.o sradio.o
Another implicit rule: only the prerequisites are given for the target “startup”. The “make” program knows itself how to call the linker in order to make the executable. We help it a bit with the definition of “LDFLAGS” higher up.
clean: rm -f *.o startup make.dep
When everything else fails, it may be that all these rules didn’t do what was intended. So it’s good to call “make clean” and “make”.
(Un)installation
install: all install -D -m 6100 startup $(INSTALLDIR)/bin/startup uninstall: rm -f $(INSTALLDIR)/bin/startup
The only catch here is the ‘-m 6100’ argument for the install-program. This simply sets ‘chmod a+s’ the startup-program. Like this, normal users may start the ‘startup’ program, too.
BTS and MS Makefile
The BTS and the MS are more or less identical with the Frontend-Makefile for the biggest part of them. One speciality is in the fact, that both use the same directories for the sources, but that the objects of both are stored in a special directory. In order to switch between the two compiling-styles, a flag is set during compilation, using the ‘-D’ option from gcc. So, let’s have a look at how to use make’s capabilities for accomplishing this task:
Variable declaration
include ../rtl_O.mk CC = kgcc L1_PATH = ../L1_DSP DAQ_PATH = ../DAQ L2_PATH = ../L2 CFLAGS += -DMS -I$(DAQ_PATH)/ -I$(L1_PATH)/ -I$(L2_PATH) -DTWOFOUR -DLINUX $(INCLUDE) L1_SOURCES = L1_ms_thread.c L1a_thread.c L1_misc.c L1_mapping.c L1_spreading.c \ L1_midamble.c L1_filter.c L1_synch_prim.c L1_data.c L1_slot.c \ L1_main_functions.c L1_channel_estimation.c L1_matched_filter.c \ L1a_decode.c L1a_parity.c L1a_xmit.c L1_Gain_Control.c \ L1_Adjust_Sync.c DAQ_SOURCES = daq.c daq_gains.c daq_freq.c daq_test.c fpga_setup.c SOURCES := $(L1_SOURCES:%=$(L1_PATH)/%) $(DAQ_SOURCES:%=$(DAQ_PATH)/%) L1_OBJ = $(L1_SOURCES:.c=.o) DAQ_OBJ = $(DAQ_SOURCES:.c=.o) OBJ = $(L1_OBJ) $(DAQ_OBJ)
The first interesting declaration is CFLAGS. As rtl_O.mk defines itself the CFLAGS variable, we need to add to it, using ‘+=’`. There we see the flag ‘-DMS’ that is used to tell the source that it is compiled for a MobileStation. The flag ‘-DTWOFOUR’ sets some structures to be used with linux-2.4.x.
Then we have SOURCES. First of all, we define it statically, that is once and for all. ‘:=’ implies this. If L1_SOURCES is changed at a later time, SOURCES won’t change. After this we have an interesting substitution in the definition of SOURCES: ‘%=$(L1_PATH)/%’. The ‘%’ sign is about the same as the ‘*’ is to bash. It fit’s everything. But, as this is ‘make’, it fits everything for one file. So, first it fits ‘L1_ms_thread.c’, then ‘L1a_thread.c’ and so on. This is changed to ‘$(L1_PATH)/%’. Here, the ‘%’ sign stands for the part that it matched before. So, ‘L1_ms_thread.c’ changes to ‘../L1_DSP/L1_ms_thread.c’.
The substitution in L1_OBJ is already explained further up. Let’s just say that this is equivalent to
L1_OBJ = $(L1_SOURCES:%.c=%.o) DAQ_OBJ = $(DAQ_SOURCES:.c=.o) OBJ = $(L1_OBJ) $(DAQ_OBJ)
Makefiles are very nice, once they are understood!
Dependencies across directories
all: make.dep $(OBJ) daq_module.o SR_driver.o dep make.dep: $(CC) -MM $(SOURCES) $(CFLAGS) > make.dep ifeq (make.dep, $(wildcard make.dep)) include make.dep endif
The tricky part here is to understand how the ‘-MM’ switch of gcc works. Let’s look at one of the dependencies generated by gcc:
L1_bs_thread.o: ../L1_DSP/L1_bs_thread.c \ /usr/src/rtlkernel-2.4.4-rtl/include/linux/modversions.h ../DAQ/daq.h \ ../DAQ/daq_ext.h ../L1_DSP/L1_structs.h ../L1_DSP/L1a_structs.h \ ../DAQ/daq_proto.h ../L1_DSP/L1_proto.h ../L1_DSP/L1_extern.h
So, here we see that gcc writes it the way we want it to (magic): our object file shall be in the current directory, and it’s dependency have to be in the corresponding source-directories.
More rules
Now that we have defined the sources and the OBJs, we could think that ‘make’ may use one of its famous explicit rules and finish the job. Unfortunatly this is too complicated for ‘make’. Or this is not the standard case. What make does without further intervention, is to compile everything and put the object-files into the source-directory. This is not what we want, as the BS will also write it’s file in the same directory, and thus it would clash. So we have to tell ‘make’ that it has to write the object files in our own directory:
$(L1_OBJ): $(CC) $(CFLAGS) -c $(L1_PATH)/$(@:.o=.c) $(DAQ_OBJ): $(CC) $(CFLAGS) -c $(DAQ_PATH)/$(@:.o=.c)
Of course ‘make’ allows us to set variables as rules. This way everytime make wants to get one of the objects, it falls into the corresponding rule and calls ‘gcc’ with the appropriate variables. The third argument here is another substitution: ‘@’ is the current target’s name. So if ‘make’ decided to redo ‘L1_ms_thread.o’, ‘$(@)’ is substituted with this, and we tell make to substitute the .o into .c so that in the end a call is done like
$(CC) $(CFLAGS) -c ../L1_DSP/L1_ms_thread.c
which puts the resulting object-file in the current directory.
SR_driver.o : $(L2_PATH)/SR_driver.c $(CC) $(CFLAGS) -c $(L2_PATH)/SR_driver.c daq_module.o : $(OBJ) $(LD) -r $(OBJ) -o daq_module.o
Two rules that you should understand now. Only speciality is the call to $(LD), which defaults to ‘ld’. The switch ‘-r’ permits the linker to generate modules that are readable by the kernel.
And the rest
install: all install -d $(INSTALLDIR)/lib/BTS install -m 444 SR_driver.o daq_module.o $(INSTALLDIR)/lib/BTS uninstall: rm -rf $(INSTALLDIR)/lib/BTS clean: rm -f *.o $(L1_PATH)/*.o $(DAQ_PATH)/*.o make.dep
Again, nothing new here. The ‘Makefile’ in ‘Radio/BTS’ is about the same structure, the only difference is the switch all at the beginning, where CFLAGS is defined a bit differently:
CFLAGS += -DBTS -I$(DAQ_PATH)/ -I$(L1_PATH)/ -I$(L2_PATH) -DTWOFOUR -DLINUX $(INCLUDE)
The ‘-DBTS’ prepares the source for compiling as a Base Station.
This was a short introduction to make and Makefiles, brought to you by Linus Gasser email-me for any questions.
RPMs
Shortest RPM-HowTo
Preparation
Before you think about putting your code into an RPM, it is much useful if you have at least three targets in your Makefile:
- clean
- removed all generated files
- all
- compile all necessary files
- install
- copy the files into the system directories
It is important that after make install the binaries are well installed, and that even after removal of the source-direcotry, the program still runs. Furthermore it is necessary to have an optional variable for the Makefile, preferably called RPM_BUILD_ROOT, that is prefixed on all installed files. So, for example, if RPM_BUILD_ROOT points to /tmp/rpm, a file usually installed in /usr/bin would be installed in /tmp/rpm/usr/bin. Once you have done this, you may take the next step: The spec file
Spec-files
If you are working with xemacs (I advise you too, but vi seems to be pretty OK, too), you can open a new file in your project-directory that is called <project_name>.spec XEmacs then will fill it with the standard lines. I will go through the lines from Etrans.spec, the specification-file used in the Etrans-project: </project_name>
Summary: Etrans - the Software Radio from EPFL/Eurecom Name: Etrans Version: 0.3 Release: 1 URL: http://lcmpc10.epfl.ch] Source0: %{name}-%{version}.tar.gz License: GPL Group:Development/System BuildRoot: %{_tmppath}/%{name}-root Requires: rtlkernel = 2.4.4rtl rtlinux = 3.1 %description This is a remake of the software radio originally written by Raymond Knopp and others. It is put in a usable shape, bound with a frontend and should also get some documentation. %prep %setup -q %build make %install rm -rf $RPM_BUILD_ROOT make install %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) /opt/radio /etc/profile.d /dev/daq0 %changelog * Tue Mar 5 2002 root <> - Initial build.
We will no go through the file line by line and look what this rpm-spec file is all about:
-
Summary is a one-liner for a description.
-
Name is the base-name of your Project. It has to match with your directory-name and with the name of your .tgz In our example the project Etrans in it’s version 0.3 is stored in a directory called Etrans-0.3 and it’s source-tarball is called Etrans-.0.3.tgz So the name would be Etrans
-
Version In our example, this is 0.3
-
URL is an optional URL where the source can be get
-
License should be GPL, but of course may differ
-
Group is one of the groups described in /usr/share/doc/rpm-4.0.3/GROUPS
-
Requires gives a list of packages that need to be installed. It is important to have a space before and after the ‘=’, ifnot the file ‘rtlkernel=2.4.4rtl’ is expected.
-
description is a longer description
-
build commands to build the binaries. In some cases you may want to include a ./configure here.
-
install the variable RPM_BUILD_ROOT is created in the prep step and points to the base directory for the installation. ‘make install’ then puts the files in this directory, if all is put up well. For some programs you’ll need a ‘configure –prefix=$RPM_BUILD_ROOT’ in the build stage. But Etrans looks directly for the environment-variable RPM_BUILD_ROOT and puts the files under this directory
-
clean after the binaries are taken from the install-directory, this is called to clean up the installation-directory. The command presented here is a bit of a security-hazard, as RPM_BUILD_ROOT may point to ‘/’ and thus the whole filesystem would be deleted.
-
files indicates which files need to be taken into the rpm-package. All names and directories are relative to $RPM_BUILD_ROOT. If a name points to a directory, it is stepped through recursively and all files are included in the rpm.
-
changelog don’t forget to update your changes
Building of RPM
Once you have your spec-file, you only need to pack up your project and let it build:
tar cvzf Etrans-0.3.tar.gz Etrans-0.3/. rpmbuild -ta Etrans-0.3.tar.gz
The ‘.’ in Etrans-0.3/. is there because on my system, Etrans-0.3 is a symbolic link. So rather than tarring a symbolic link, I’d like to tar the content of this symbolic link! The second command then does everything from decompressing the tar.gz to calling all necessary scripts and building up a rpm. If all goes right, you can find your rpm in
/usr/src/redhat/RPMS/i386
If you’re on an intel machine, of course. Try the file on a clean, freshly installed machine, to look if you didn’t forget any dependencies.