Suggestions for Shell Scripts for Building Large FiveLinux A

Post Reply
User avatar
xProgrammer
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Suggestions for Shell Scripts for Building Large FiveLinux A

Post by xProgrammer »

Hi All

My biggest FiveLinux application currently has 11 xHarbour source files. I built a shell script (based on buildx.sh) to build the application. One problem I encountered was that the script didn't stop if it encountered an error so you weren't immediately aware of the problem. And the error messages would be shifted off the screen by the batch file continuing. Mind you I had inadvertantly exaccerbated the problem by not automatically deleting the previously generated .c and .o files which meant that executable code might still be generated - but just not from the source intended.

I set out to improve upon the script.

The first step was to notify immediately an error occurred and stop execution at that point. Rather than have to put the same code in for every compile (both harbour and gcc) I found a neat shell script function:

Code: Select all

check_errs()
{
  # Function. Parameter 1 is the return code
  # Para. 2 is text to display on failure.
  if [ "${1}" -ne "0" ]; then
    echo "ERROR # ${1} : ${2}"
    # as a bonus, make our script exit with the right error code.
    exit ${1}
  fi
}
so after each compile you only have to add something like:

Code: Select all

check_errs $? "compiling mSYS.c to object code"
But why not take this kind of approach further. By that I mean that each harbour source compilation requires the same basic code along the following lines:

Code: Select all

echo compiling mSYS C module...
gcc mSYS.c -c -I./../include -I./../../xharbour/include `pkg-config --cflags gtk+-2.0`
check_errs $? "compiling mSYS.c to object code"
So why not wrap that up into a function? Which is what I did as follows:

Code: Select all

compile_prg()
{
  # Function. Parameter 1 is the module name  
  echo compiling $1.prg xHarbour code to C code
  ./../../xharbour/bin/harbour $1.prg -n -I./../include -I./../../xharbour/include
  check_errs $? "compiling ${1}.prg"
}
That means that to compile my mSYS xHarbour source file all I need in my script is:

Code: Select all

compile_prg mSYS
Simple! So why not do the same thing for compiling the generated C code to object code - not to forget then deleting the C code. So I wrote the following function:

Code: Select all

compile_c()
{
  # Function. Parameter 1 is the module name
  echo compiling $1.c to object code
  gcc $1.c -c -I./../include -I./../../xharbour/include `pkg-config --cflags gtk+-2.0`
  check_errs $? "compiling ${1}.c"
  rm $1.c
}
That means that I can replace:

Code: Select all

echo compiling mSYS C module...
gcc mSYS.c -c -I./../include -I./../../xharbour/include `pkg-config --cflags gtk+-2.0`
check_errs $? "compiling mSYS.c to object code"
rm mSYS.c
with:

Code: Select all

compile_c mSYS
Much simpler. There are added bonuses too. Like if I want to switch compilers or the layout of my programming tools on my hard disk I only have to edit in one place (the functions above). Also the script is now highly readable. Much more xBase like!

So currently my build file looks like this:

Code: Select all

# ./mb.sh

check_errs()
{
  # Function. Parameter 1 is the return code
  # Para. 2 is text to display on failure.
  if [ "${1}" -ne "0" ]; then
    echo "ERROR # ${1} : ${2}"
    # as a bonus, make our script exit with the right error code.
    exit ${1}
  fi
}

compile_prg()
{
  # Function. Parameter 1 is the module name  
  echo compiling $1.prg xHarbour code to C code
  ./../../xharbour/bin/harbour $1.prg -n -I./../include -I./../../xharbour/include
  check_errs $? "compiling ${1}.prg"
}

compile_c()
{
  # Function. Parameter 1 is the module name
  echo compiling $1.c to object code
  gcc $1.c -c -I./../include -I./../../xharbour/include `pkg-config --cflags gtk+-2.0`
  check_errs $? "compiling ${1}.c"
  rm $1.c
}


echo
echo Building mSYS Medical Software
echo ------------------------------
echo

echo compiling xHarbour source files
compile_prg mSYS
compile_prg mTEMLIST
compile_prg xOBJECTS
compile_prg PATIENT_Class
compile_prg PATFILE_Class
compile_prg EXTEND5
compile_prg DOCTOR_Classes
compile_prg OSTEO_Class
compile_prg SINGLE_Class
compile_prg xPATIENT_Class
compile_prg RECORD_Class

echo compiling generated C files
compile_c mSYS
compile_c mTEMLIST
compile_c xOBJECTS
compile_c PATIENT_Class
compile_c PATFILE_Class
compile_c EXTEND5
compile_c DOCTOR_Classes
compile_c OSTEO_Class
compile_c SINGLE_Class
compile_c xPATIENT_Class
compile_c RECORD_Class

echo linking...
gcc mSYS.o  mTEMLIST.o xOBJECTS.o PATIENT_Class.o PATFILE_Class.o EXTEND5.o DOCTOR_Classes.o OSTEO_Class.o SINGLE_Class.o RECORD_Class.o -omSYS -L./../lib -L./../../xharbour/lib `pkg-config --libs gtk+-2.0` `pkg-config --libs libglade-2.0` `pkg-config --libs libgnomeprintui-2.2` -Wl,--start-group -lfivex -lfivec -lcommon -lvm -lrtl -lrdd -lmacro -llang -lcodepage -lpp -ldbfntx -ldbfcdx -ldbffpt -lhbsix -lhsx -lpcrepos -lusrrdd -ltip -lct -lcgi -lgtnul -lgtstd -lgtcgi -lgtcrs -lhbodbc -ldebug -lm -lgpm -lncurses -Wl,--end-group

echo removing .o files
rm mSYS.o
rm mTEMLIST.o
rm xOBJECTS.o
rm PATIENT_Class.o
rm PATFILE_Class.o
rm EXTEND5.o
rm DOCTOR_Classes.o
rm SINGLE_Class.o
rm xPATIENT_Class.o
rm RECORD_Class.o

echo done!
Whereto from here? Well maybe we can somehow create a list of modules and use that list throughout. But I'll have to do some more research on shell script capabilities to see if I can find a way to do that. In the meantime I'm pretty happy with the script as it stands. I certainly think it suits me a lot better than my old one.

Happy programming
xProgrammer
User avatar
xProgrammer
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Better Yet

Post by xProgrammer »

Hi all

I should have thought of it at the time. There's no reason not to do the two compilation steps (prg to C then C to object) for each module one after the other.

So compile_prg() becomes:

Code: Select all

{
  # Function. Parameter 1 is the module name  
  echo compiling $1.prg xHarbour code to C code
  ./../../xharbour/bin/harbour $1.prg -n -I./../include -I./../../xharbour/include
  check_errs $? "compiling ${1}.prg"
  echo compiling $1.c to object code
  gcc $1.c -c -I./../include -I./../../xharbour/include `pkg-config --cflags gtk+-2.0`
  check_errs $? "compiling ${1}.c"
  rm $1.c
}
and each compile_prg line does the work of the previous compile_prg and compile_c

So my script is now somewhat shorter at:

Code: Select all

# ./mb.sh

check_errs()
{
  # Function. Parameter 1 is the return code
  # Para. 2 is text to display on failure.
  if [ "${1}" -ne "0" ]; then
    echo "ERROR # ${1} : ${2}"
    # as a bonus, make our script exit with the right error code.
    exit ${1}
  fi
}

compile_prg()
{
  # Function. Parameter 1 is the module name  
  echo compiling $1.prg xHarbour code to C code
  ./../../xharbour/bin/harbour $1.prg -n -I./../include -I./../../xharbour/include
  check_errs $? "compiling ${1}.prg"
  echo compiling $1.c to object code
  gcc $1.c -c -I./../include -I./../../xharbour/include `pkg-config --cflags gtk+-2.0`
  check_errs $? "compiling ${1}.c"
  rm $1.c
}

echo
echo Building mSYS Medical Software
echo ------------------------------
echo

echo compiling xHarbour source files
compile_prg mSYS
compile_prg mTEMLIST
compile_prg xOBJECTS
compile_prg PATIENT_Class
compile_prg PATFILE_Class
compile_prg EXTEND5
compile_prg DOCTOR_Classes
compile_prg OSTEO_Class
compile_prg SINGLE_Class
compile_prg xPATIENT_Class
compile_prg RECORD_Class

echo linking...
gcc mSYS.o  mTEMLIST.o xOBJECTS.o PATIENT_Class.o PATFILE_Class.o EXTEND5.o DOCTOR_Classes.o OSTEO_Class.o SINGLE_Class.o RECORD_Class.o -omSYS -L./../lib -L./../../xharbour/lib `pkg-config --libs gtk+-2.0` `pkg-config --libs libglade-2.0` `pkg-config --libs libgnomeprintui-2.2` -Wl,--start-group -lfivex -lfivec -lcommon -lvm -lrtl -lrdd -lmacro -llang -lcodepage -lpp -ldbfntx -ldbfcdx -ldbffpt -lhbsix -lhsx -lpcrepos -lusrrdd -ltip -lct -lcgi -lgtnul -lgtstd -lgtcgi -lgtcrs -lhbodbc -ldebug -lm -lgpm -lncurses -Wl,--end-group

echo removing .o files
rm mSYS.o
rm mTEMLIST.o
rm xOBJECTS.o
rm PATIENT_Class.o
rm PATFILE_Class.o
rm EXTEND5.o
rm DOCTOR_Classes.o
rm SINGLE_Class.o
rm xPATIENT_Class.o
rm RECORD_Class.o

echo done!
Regards
xProgrammer
User avatar
xProgrammer
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Partial Implementation of Lists

Post by xProgrammer »

Hi all

I have found out how to use lists in the bash shell (The default shell for users under Ubuntu). Note that this code would need modification to run under other shells.

Using this approach the we create a list of module names that is then used in both compiling the modules and removing the object files. It would be nice to use the list also in the link step but we need to add .o to each element in the list. That should be possible but may have to wait for another day. Maybe someone can help out.

In the meantime my script now looks like this:

Code: Select all

# ./mb.sh

check_errs()
{
  # Function. Parameter 1 is the return code
  # Para. 2 is text to display on failure.
  if [ "${1}" -ne "0" ]; then
    echo "ERROR # ${1} : ${2}"
    # as a bonus, make our script exit with the right error code.
    exit ${1}
  fi
}

compile_prg()
{
  # Function. Parameter 1 is the module name  
  echo compiling $1.prg xHarbour code to C code
  ./../../xharbour/bin/harbour $1.prg -n -I./../include -I./../../xharbour/include
  check_errs $? "compiling ${1}.prg"
  echo compiling $1.c to object code
  gcc $1.c -c -I./../include -I./../../xharbour/include `pkg-config --cflags gtk+-2.0`
  check_errs $? "compiling ${1}.c"
  rm $1.c
}

echo
echo Building mSYS Medical Software
echo ------------------------------
echo

sources="mSYS 
mTEMLIST 
xOBJECTS 
PATIENT_Class 
PATFILE_Class 
EXTEND5 
DOCTOR_Classes 
OSTEO_Class 
SINGLE_Class
xPATIENT_Class 
RECORD_Class"
for m in ${sources}
do
  compile_prg ${m}
done


echo linking...
gcc mSYS.o  mTEMLIST.o xOBJECTS.o PATIENT_Class.o PATFILE_Class.o EXTEND5.o DOCTOR_Classes.o OSTEO_Class.o SINGLE_Class.o RECORD_Class.o -omSYS -L./../lib -L./../../xharbour/lib `pkg-config --libs gtk+-2.0` `pkg-config --libs libglade-2.0` `pkg-config --libs libgnomeprintui-2.2` -Wl,--start-group -lfivex -lfivec -lcommon -lvm -lrtl -lrdd -lmacro -llang -lcodepage -lpp -ldbfntx -ldbfcdx -ldbffpt -lhbsix -lhsx -lpcrepos -lusrrdd -ltip -lct -lcgi -lgtnul -lgtstd -lgtcgi -lgtcrs -lhbodbc -ldebug -lm -lgpm -lncurses -Wl,--end-group

echo removing .o files
for m in ${sources}
do
  rm ${m}.o
done

echo done!
See you all
xProgrammer
User avatar
xProgrammer
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Some More Ideas

Post by xProgrammer »

Hi all

This could be extended.

For starters staying with shell scripting we could write scripts for updating libfivex and libfivec from fivelinux/source/classes and /fivelinux/source/winapi. Or make them command line options. We could have options to automatically run the executable on successful compile and link, or give the user the option. We could separate the project dependant and project independant parts into two separate scripts so the specific script for any project is smaller and we aren't cutting and pasting all the time. We could have a command line option for which compiler to use (xHarbour or Harbour)

Then going beyond shell script I believe we could write a project manager in xHarbour / FiveLinux.

I may be the only one currently writing FiveLinux apps with this number of source files? So may be noone else is interested. But if anyone else is I would be happy to work with them.

Happy programming
xProgrammer
User avatar
xProgrammer
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Post by xProgrammer »

Hi all

I found a fairly neat way to build up the list of object files produced from the prg modules. The syntax used was, I believe, only introduced in version 3.1 of the bash shell so you may need to adjust it on an old OS. So my adjusted script now looks like this:

Code: Select all

# ./mb.sh

check_errs()
{
  # Parameter 1 is the return code
  # Parameter 2 is text to display on failure.
  if [ "${1}" -ne "0" ]; then
    echo "ERROR # ${1} : ${2}"
    exit ${1}
  fi
}

compile_prg()
{
  # Parameter 1 is the module name  
  echo compiling $1.prg xHarbour code to C code
  ./../../xharbour/bin/harbour $1.prg -n -I./../include -I./../../xharbour/include
  check_errs $? "compiling ${1}.prg"
  echo compiling $1.c to object code
  gcc $1.c -c -I./../include -I./../../xharbour/include `pkg-config --cflags gtk+-2.0`
  check_errs $? "compiling ${1}.c"
  rm $1.c
}

echo
echo Building mSYS Medical Software
echo ------------------------------
echo

sources="mSYS 
mTEMLIST 
xOBJECTS 
PATIENT_Class 
PATFILE_Class 
EXTEND5 
DOCTOR_Classes 
OSTEO_Class 
SINGLE_Class
xPATIENT_Class 
RECORD_Class"

objects=""
for m in ${sources}
do
  compile_prg ${m}
  objects+=" ${m}.o"
done
libs="-lfivex -lfivec -lcommon -lvm -lrtl -lrdd -lmacro -llang -lcodepage -lpp -ldbfntx -ldbfcdx -ldbffpt -lhbsix -lhsx -lpcrepos -lusrrdd -ltip -lct -lcgi -lgtnul -lgtstd -lgtcgi -lgtcrs -lhbodbc -ldebug -lm -lgpm -lncurses"
ldirs="-L./../lib -L./../../xharbour/lib"
cfigs="`pkg-config --libs gtk+-2.0` `pkg-config --libs libglade-2.0` `pkg-config --libs libgnomeprintui-2.2`"

echo linking...
gcc ${objects} -omSYS ${ldirs} ${cfigs} -Wl,--start-group ${libs} -Wl,--end-group

echo removing .o files
for m in ${sources}
do
  rm ${m}.o
done

echo done!
I took the opportunity to split out the long line doing the link step.

Regards
xProgrammer
User avatar
Antonio Linares
Site Admin
Posts: 37481
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Post by Antonio Linares »

Dear Doug,

For managing multiple PRG and C files we do recommend to use a make file. They are quite easy to build and work great in Linux (and also in Mac).

Thats how we build FiveLinux and FiveMac :-)

I can prepare an example for you.
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
Posts: 37481
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Post by Antonio Linares »

simply type "make" from the terminal and it will build the default "makefile"

makefile

Code: Select all

# makefile sample

all : ./test

PRG_OBJS = ./obj/test.o        \
           ./obj/another.o     \
           ./obj/onemore

C_OBJS = ./objc/cfile.o

./test : $(PRG_OBJS) $(C_OBJS)
#linking code goes here

./obj/%.c : ./%.prg
	harbour $< -o./$@ -n -I./../harbour/include -I./include

./obj/%.o : ./obj/%.c
               gcc -c -o $@ -I./../harbour/include $<
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
xProgrammer
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Post by xProgrammer »

Hi Antonio

Thanks for the info on make.

But I've gone a bit further down the track with my system and I think its now even easier. I have split out the stuff that is project dependant from the rest and put it in a five linux project file (which gets included in the script). Mine is called msys.flp and looks like this:

Code: Select all

#!/bin/bash

appname="mSYS Medical Software"
output="mSYS"
sources="mSYS 
mTEMLIST 
xOBJECTS 
PATIENT_Class 
PATFILE_Class 
EXTEND5 
DOCTOR_Classes 
OSTEO_Class 
SINGLE_Class
xPATIENT_Class 
RECORD_Class"
Pretty simple!

Then all I have to do is call my main script passing it the name of this project file (minus the assumed .flp extension).

So I would type

Code: Select all

./m.sh msys
The script m.sh is as follows. The line

Code: Select all

 . ${1}.flp
includes the flp file's contents at that point.

Code: Select all

#!/bin/bash
# m.sh

if [ $# = 0 ]; then
   echo syntax: ./m.sh project
   echo where project is the name of the Five Linux project [.flp] file
   exit
fi

check_errs()
{
  # Parameter 1 is the return code
  # Parameter 2 is text to display on failure.
  if [ "${1}" -ne "0" ]; then
    echo "ERROR # ${1} : ${2}"
    exit ${1}
  fi
}

compile_prg()
{
  # Parameter 1 is the module name  
  echo compiling $1.prg xHarbour code to C code
  ./../../xharbour/bin/harbour $1.prg -n -I./../include -I./../../xharbour/include
  check_errs $? "compiling ${1}.prg"
  echo compiling $1.c to object code
  gcc $1.c -c -I./../include -I./../../xharbour/include `pkg-config --cflags gtk+-2.0`
  check_errs $? "compiling ${1}.c"
  rm $1.c
}

. ${1}.flp
echo
echo Building ${appname}
echo


objects=""
for m in ${sources}
do
  compile_prg ${m}
  objects+=" ${m}.o"
done
libs="-lfivex -lfivec -lcommon -lvm -lrtl -lrdd -lmacro -llang -lcodepage -lpp -ldbfntx -ldbfcdx -ldbffpt -lhbsix -lhsx -lpcrepos -lusrrdd -ltip -lct -lcgi -lgtnul -lgtstd -lgtcgi -lgtcrs -lhbodbc -ldebug -lm -lgpm -lncurses"
ldirs="-L./../lib -L./../../xharbour/lib"
cfigs="`pkg-config --libs gtk+-2.0` `pkg-config --libs libglade-2.0` `pkg-config --libs libgnomeprintui-2.2`"

echo linking...
gcc ${objects} -o${output} ${ldirs} ${cfigs} -Wl,--start-group ${libs} -Wl,--end-group

echo removing .o files
for m in ${sources}
do
  rm ${m}.o
done

echo done!
I think that this might be a trifle less intimidating than make for people who are relatively new to Linux (me included!) All you have to do is build the .flp file with a text editor - the format could hardly be easier. It wouldn't take much to build a FiveLinux app to do it for beginners and it could even run the whole process using WinExec(). I think its worth looking at.

Regards
Doug
xProgrammer
User avatar
xProgrammer
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Post by xProgrammer »

Hi all

I have (in a very crude way) built FiveLinux application compile and link into a Five Linux application with this very simplistic code:

Code: Select all

FUNCTION Compile( xProject )

LOCAL sOsCommand

sOsCommand := "./m.sh " + xProject + " > test.txt" 
RUN ( sOsCommand )
MsgInfo( MemoRead( "test.txt" ) )

RETURN nil
The only change that was sort of required to my previous m.sh script was to add the "really quiet" (-q0) option to the line invoking the xHarbour compiler, that is:

Code: Select all

  ./../../xharbour/bin/harbour $1.prg -n -I./../include -I./../../xharbour/include -q0
That was only required to make the captured output less bulky and easier to read. I note that this option is listed as /q0 on the harbour-project.org site.

I also took the opportunity to modify some of the echo lines. I will alter its name to x.sh (for xharbour) and potentially have an h.sh (for harbour)

At some point in time I'll put this basic idea to use in a mini project manager.

Regards
xProgrammer
Post Reply