Writing the Fortran 90 Implementation

Before writing the client, let's generate a Fortran implementation as well. It is highly instructive to see how the makefiles differ between the different language bindings. From within the minimal/libCxx directory we do.

% cd ../libF90
% babel -makefile -sF90 ../../hello.sidl

This time there's even more files generated (Fortran 90 bindings are harder after all), and we need to add our implementation to the Hello_World_Impl.F90 file. The modified code will look like this.


   1 !
   2 ! Method:  getMsg[]
   3 !
   4 
   5 recursive subroutine Hello_World_getMsg_mi(self, retval, exception)
   6   use sidl
   7   use sidl_BaseInterface
   8   use sidl_RuntimeException
   9   use Hello_World
  10   use Hello_World_impl
  11   ! DO-NOT-DELETE splicer.begin(Hello.World.getMsg.use)
  12   ! Insert-Code-Here {Hello.World.getMsg.use} (use statements)
  13   ! DO-NOT-DELETE splicer.end(Hello.World.getMsg.use)
  14   implicit none
  15   type(Hello_World_t) :: self ! in
  16   character (len=*) :: retval ! out
  17   type(sidl_BaseInterface_t) :: exception ! out
  18  
  19 ! DO-NOT-DELETE splicer.begin(Hello.World.getMsg)
  20 retval='Hello from Fortran 90!'
  21 ! DO-NOT-DELETE splicer.end(Hello.World.getMsg)
  22 end subroutine Hello_World_getMsg_mi
  23  

Note that the C function appears as a subroutine in Fortran. What was the return value appears here as the argument retval (line 5). For Fortran 90 there are also two splicer blocks per subroutine, one for use statements (lines 11-13) and another for the actual implementation (lines 19-21). This is where we put our implementation by setting retval to the string we want.

There are important differences in this Makefile from the C++ implementation, so we reproduce it in its entirety here.


   1 include babel.make
   2 # please name the server library here
   3 LIBNAME=hello
   4 # please name the SIDL file here
   5 SIDLFILE=../../hello.sidl
   6 # extra include/compile flags 
   7 EXTRAFLAGS=
   8 # extra librarys that the implementation needs to link against
   9 EXTRALIBS=
  10 # library version number
  11 VERSION=0.1.1
  12 # PREFIX specifies the top of the installation directory
  13 PREFIX=/usr/local
  14 # the default installation installs the .la and .scl (if any) into the
  15 # LIBDIR
  16 LIBDIR=$(PREFIX)/lib
  17 # the default installation installs the stub header and IOR header files
  18 # in INCLDIR
  19 INCLDIR=$(PREFIX)/include
  20 
  21 # most of the rest of the file should not require editing
  22 
  23 ifeq ($(IMPLSRCS),)
  24   SCLFILE=
  25   BABELFLAG=--client=f90
  26   MODFLAG=
  27 else
  28   SCLFILE=lib$(LIBNAME).scl
  29   BABELFLAG=--server=f90
  30   MODFLAG=-module
  31 endif
  32 
  33 all : lib$(LIBNAME).la $(SCLFILE)
  34 
  35 CC=`babel-config --query-var=CC`
  36 CPP=`babel-config --query-var=CPP`
  37 FC=`babel-config --query-var=FC`
  38 INCLUDES=`babel-config --includes` `babel-config --includes-f90`
  39 CFLAGS=`babel-config --flags-c`
  40 FCFLAGS=`babel-config --flags-f90`
  41 MODINCLUDES=`babel-config --includes-f90-mod`
  42 LIBS=`babel-config --libs-f90-client`
  43 F90CPPSUFFIX=`babel-config --query-var=F90CPPSUFFIX`
  44 
  45 STUBOBJS=$(STUBSRCS:.c=.lo)
  46 STUBMODULEOBJS=$(STUBMODULESRCS:.F90=.lo)
  47 TYPEMODULEOBJS=$(TYPEMODULESRCS:.F90=.lo)
  48 IOROBJS=$(IORSRCS:.c=.lo)
  49 SKELOBJS=$(SKELSRCS:.c=.lo)
  50 IMPLOBJS=$(IMPLSRCS:.F90=.lo)
  51 IMPLMODULEOBJS=$(IMPLMODULESRCS:.F90=.lo)
  52 BASICMODULEOBJ=$(BASICMODULESRC:.F90=.lo)
  53 ARRAYMODULEOBJS=$(ARRAYMODULESRCS:.F90=.lo)
  54 ALLOBJS=$(STUBOBJS) $(STUBMODULEOBJS) $(TYPEMODULEOBJS) $(IOROBJS) \
  55 	$(SKELOBJS) $(IMPLOBJS) $(IMPLMODULEOBJS) $(BASICMODULEOBJ) \
  56 	$(ARRAYMODULEOBJS)
  57 
  58 PUREBABELGEN=$(ARRAYMODULESRCS) $(BASICMODULESRC) $(STUBMODULESRCS) \
  59 	$(TYPEMODULESRCS) \
  60 	$(IORHDRS) $(IORSRCS) $(STUBSRCS) $(STUBHDRS) $(SKELSRCS)
  61 BABELGEN=$(IMPLSRCS) $(IMPLMODULESRCS)
  62 
  63 $(TYPEMODULEOBJS)  : $(BASICMODULEOBJ)
  64 $(ARRAYMODULEOBJS)  : $(TYPEMODULEOBJS)
  65 $(STUBMODULEOBJS) : $(ARRAYMODULEOBJS) $(TYPEMODULEOBJS)
  66 $(IMPLMODULEOBJS) : $(STUBMODULEOBJS)
  67 $(IMPLOBJS) : $(IMPLMODULEOBJS) $(STUBMODULEOBJS) \
  68 
  69 lib$(LIBNAME).la : $(ALLOBJS)
  70 	babel-libtool --mode=link --tag=FC $(FC) -o lib$(LIBNAME).la \
  71 	  -rpath $(LIBDIR) -release $(VERSION) \
  72 	  -no-undefined $(MODFLAG) \
  73 	  $(FCFLAGS) $(EXTRAFLAGS) $^ $(LIBS) \
  74 	  $(EXTRALIBS)
  75 
  76 $(PUREBABELGEN) $(BABELGEN) : babel-stamp
  77 	@if test -f $@; then \
  78 	    touch $@; \
  79 	else \
  80 	    rm -f babel-stamp ; \
  81 	    $(MAKE) babel-stamp; \
  82 	fi
  83 
  84 babel-stamp: $(SIDLFILE)
  85 	@rm -f babel-temp
  86 	@touch babel-temp
  87 	babel $(BABELFLAG) $(SIDLFILE) 
  88 	@mv -f babel-temp $@
  89 
  90 lib$(LIBNAME).scl : $(IORSRCS)
  91 ifeq ($(IORSRCS),)
  92 	echo "lib$(LIBNAME).scl is not needed for client-side C bindings."
  93 else
  94 	-rm -f $@
  95 	echo '<?xml version="1.0" ?>' > $@
  96 	echo '<scl>' >> $@	
  97 	if test `uname` = "Darwin"; then scope="global"; else scope="local"; \
  98 	   fi ; \
  99           echo ' <library uri="'`pwd`/lib$(LIBNAME).la'" scope="'"$$scope"'" resolution="lazy" >' >> $@
 100 	grep __set_epv $^ /dev/null | awk 'BEGIN {FS=":"} { print $$1}' | sort -u | sed -e 's/_IOR.c//g' -e 's/_/./g' | awk ' { printf "    <class name=\"%s\" desc=\"ior/impl\" />\n", $$1 }' >>$@
 101 	echo "  </library>" >>$@
 102 	echo "</scl>" >>$@
 103 endif
 104 
 105 .SUFFIXES: .lo .F90 .c
 106 
 107 .c.lo:
 108 	babel-libtool --mode=compile --tag=CC $(CC) $(INCLUDES) $(CFLAGS) $(EXTRAFLAGS) -c -o $@ $<
 109 
 110 .F90.lo:
 111 	$(CPP) -traditional $(INCLUDES) -P -o $(@:.lo=.tmp) -x c $<
 112 	sed -e 's/^#pragma.*$$//' < $(@:.lo=.tmp) > $(@:.lo=$(F90CPPSUFFIX))
 113 	babel-libtool --mode=compile --tag=FC $(FC) $(MODINCLUDES) $(FCFLAGS) -c -o $@ $(@:.lo=$(F90CPPSUFFIX))
 114 	rm -f $(@:.lo=$(F90CPPSUFFIX)) $(@:.lo=.tmp)
 115 
 116 clean : 
 117 	-rm -f $(PUREBABELGEN) babel-temp babel-stamp *.o *.lo *.mod
 118 
 119 realclean : clean
 120 	-rm -f lib$(LIBNAME).la lib$(LIBNAME).scl
 121 	-rm -rf .libs
 122 
 123 install : install-libs install-headers install-scl
 124 
 125 
 126 install-libs : lib$(LIBNAME).la
 127 	-mkdir -p $(LIBDIR)
 128 	babel-libtool --mode=install install -c lib$(LIBNAME).la \
 129 	  $(LIBDIR)/lib$(LIBNAME).la
 130 
 131 install-scl : $(SCLFILE)
 132 ifneq ($(IORSRCS),)
 133 	-mkdir -p $(LIBDIR)
 134 	-rm -f $(LIBDIR)/lib$(LIBNAME).scl
 135 	echo '<?xml version="1.0" ?>' > $(LIBDIR)/lib$(LIBNAME).scl
 136 	echo '<scl>' >> $(LIBDIR)/lib$(LIBNAME).scl	
 137 	if test `uname` = "Darwin"; then scope="global"; else scope="local"; \
 138 	   fi ; \
 139           echo ' <library uri="'$(LIBDIR)/lib$(LIBNAME).la'" scope="'"$$scope"'" resolution="lazy" >' >> $(LIBDIR)/lib$(LIBNAME).scl
 140 	grep __set_epv $^ /dev/null | awk 'BEGIN {FS=":"} { print $$1}' | sort -u | sed -e 's/_IOR.c//g' -e 's/_/./g' | awk ' { printf "    <class name=\"%s\" desc=\"ior/impl\" />\n", $$1 }' >>$(LIBDIR)/lib$(LIBNAME).scl
 141 	echo "  </library>" >>$(LIBDIR)/lib$(LIBNAME).scl
 142 	echo "</scl>" >>$(LIBDIR)/lib$(LIBNAME).scl
 143 endif
 144 
 145 install-headers : $(IORHDRS) $(STUBHDRS) $(STUBDOCS)
 146 	-mkdir -p $(INCLDIR)
 147 	for i in $^ ; do \
 148 	  babel-libtool --mode=install cp $$i $(INCLDIR)/$$i ; \
 149 	done
 150 
 151 .PHONY: all clean realclean install install-libs install-headers install-scl

line 1:
Again Babel will generate a babel.make file, but we will see that its contents are different.
line 3:
The name of the library will be libhello.la again. This is the only line that I had to edit in the babel-generated GNUmakefile.
lines 7-19:
These variables have the same meanings as above. EXTRAFLAGS are extra compile flags, and EXTRALIBS defines extra libraries to list when linkings. PREFIX defines where the library should be installed.
lines 35-43:
Note that we use babel-config to generate the proper flag for the preprocessor to find the Babel Fortran headers, and the compiler to find the Babel MOD files.
lines 45-56:
Are building a $(OBJS) variable like before, but this time we see suffix substitutions for more kinds of files.
lines 63-67:
The order that files are compiled is important because Fortran 90's use of MOD files5.4 makes the ordering of these items very important. (Not Babel's fault, blame the Fortran 90 language designers.) C/C++ has no such constraint on the order that individual units of compilation are performed. As long as Fortran 90 programmers stick with the ordering shown in these lines, they should not encounter compiler complaints about dependent MOD files not found.
lines 110-114:
This bit of code admittedly looks very strange, but the explanation is simple. We preprocess our Fortran 90 source to workaround the 31 character limit specified in the language. Check out Chapter 9 for more details about this issue.

Again, we simply type make, and should end up with another libhello.la file.



babel-1.4.0
users_guide Last Modified 2008-10-16

http://www.llnl.gov/CASC/components
components@llnl.gov