Page 1 of 1
Automating Compile and Link
Posted: Sun Oct 04, 2009 4:39 am
by xProgrammer
Hi Antonio
I am trying to be able to compile and link code from within a code generator I am writing.
I can run the xHarbour compile step (ie .prg to .c) fine with:
FUNCTION CompilePRG( str_PRGName )
Code: Select all
LOCAL int_CompileReturn
? "Compiling " + str_PRGName + ".prg to " + str_PRGName + ".c"
int_CompileReturn := ExecuteProcess( "./../../xharbour/bin/harbour " + str_PRGName + ".prg -n -I./../include -I./../../xharbour/include" )
IF int_CompileReturn == 0
int_CompileReturn := CompileC( str_PRGName )
ENDIF
RETURN int_CompileReturn
But the C compile (.c to .o) fails. I get return value of 1. When I read from @fh_StdOut I get:
gcc: `pkg-config: No such file or directory
gcc: gtk+-2.0`: No such file or directory
cc1: error: unrecognized command line option "-fcflags"
The function is:
Code: Select all
FUNCTION CompileC( str_CName )
RETURN ExecuteProcess( "gcc " + str_CName + ".c -c -I./../include -I./../../xharbour/include `pkg-config --cflags gtk+-2.0`" )
I assume for some reason the pkg-config expansion isn't being properly recognised or can't start the process or something. Can you think of any possible work around. I could try using the RUN command but then I have to find a way to retrieve the exit code (for the solution to be ideal).
Here is my ExecuteProcess() function:
Code: Select all
FUNCTION ExecuteProcess( str_Execute )
LOCAL fh_ChildProcess
LOCAL fh_StdIn
LOCAL fh_StdOut
LOCAL fh_StdErr
LOCAL int_ReturnStatus
LOCAL str_Buffer
str_Buffer := Space(1024)
? "Starting Child Process"
fh_ChildProcess := HB_OpenProcess( str_Execute, @fh_StdIn, @fh_StdOut, @fh_StdErr )
? "Returned Process Handle is:", fh_ChildProcess
int_ReturnStatus := HB_ProcessValue( fh_ChildProcess )
? "Child Process returned status:", int_ReturnStatus
FRead( fh_StdErr, @str_Buffer, 1024 )
? "str_Buffer"
? str_Buffer
FClose( fh_ChildProcess )
FClose( fh_StdIn )
FClose( fh_StdOut )
FClose( fh_StdErr )
? "Handles closed"
RETURN int_ReturnStatus
Thanks
Doug (xProgrammer)
Re: Automating Compile and Link
Posted: Sun Oct 04, 2009 4:48 am
by xProgrammer
This works, but isn't ideal:
Code: Select all
FUNCTION CompileC( str_CName )
// RETURN ExecuteProcess( "gcc " + str_CName + ".c -c -I./../include -I./../../xharbour/include `pkg-config --cflags gtk+-2.0`" )
RUN ( "gcc " + str_CName + ".c -c -I./../include -I./../../xharbour/include `pkg-config --cflags gtk+-2.0`" )
RETURN 0
Re: Automating Compile and Link
Posted: Sun Oct 04, 2009 7:00 am
by Antonio Linares
Doug,
I would suggest to compare the source code of RUN with your ExecuteProcess() code:
Basically it does a call to:
iret = system( hb_parc( 1 ) );
http://www.cit.gu.edu.au/teaching/2501I ... cgi?system
Re: Automating Compile and Link
Posted: Sun Oct 04, 2009 8:29 am
by xProgrammer
I have pretty much solved this one.
The first problem I found was that the new process didn't seem to inherit the current working directory so I replaced the include files that were specified with relative names by absolute names.
I wrote code to get the information returned by pkg-config from a separate process. My initial attempts failed but I discovered that the problem was being caused by a carriage return at the end of the returned string which I had to filter out. So I ended up with code like this:
Code: Select all
str_Includes := GetProcessOutput( "pkg-config --cflags gtk+-2.0" )
which makes a call to the following function:
Code: Select all
FUNCTION GetProcessOutput( str_Execute )
LOCAL fh_ChildProcess
LOCAL fh_StdIn
LOCAL fh_StdOut
LOCAL fh_StdErr
LOCAL int_ReturnStatus
LOCAL str_Buffer
str_Buffer := Space(1024)
? "Starting Child Process"
fh_ChildProcess := HB_OpenProcess( str_Execute, @fh_StdIn, @fh_StdOut, @fh_StdErr )
? "Returned Process Handle is:", fh_ChildProcess
int_ReturnStatus := HB_ProcessValue( fh_ChildProcess )
? "Child Process returned status:", int_ReturnStatus
FRead( fh_StdOut, @str_Buffer, 1024 )
? "str_Buffer"
? str_Buffer
FClose( fh_ChildProcess )
FClose( fh_StdIn )
FClose( fh_StdOut )
FClose( fh_StdErr )
? "Handles closed"
RETURN RTrim( StrTran( str_Buffer, Chr( 10 ) ) )
Now I just have to get code to do the final link.
I have learned a lot from this exercise, some of which has potential application well beyond compiling and linking (x)Harbour / FiveLinux code from within an application written in the same.
Happy Programming
Doug (xProgrammer)
Re: Automating Compile and Link
Posted: Sun Oct 04, 2009 8:41 am
by xProgrammer
Hi Antonio
Thanks for the wonderfully prompt reply. I was in the middle of finding a solution without having to go to C, but I'll keep that option in mind.
It's a nice outcome from this searching for a solution that I can do a single call to pkg-config and use it for each individual file to be compiled.
I don't know if there is any relevance to a Windows environment.
Regards
Doug (xProgrammer)
Re: Automating Compile and Link
Posted: Sun Oct 04, 2009 11:59 am
by Antonio Linares
Doug,
Nice to see that you are improving and moving forward on your Linux development
Are you working on a visual make tool ?
Re: Automating Compile and Link
Posted: Mon Oct 05, 2009 3:12 am
by xProgrammer
Hi Antonio
I am building the engine to automatically build applications produced by my code generator. Currently my code generator builds a shell script that can build the application. But that is an extra step which I am working on eliminating. Originally my code generator was based on a series of functions (transformed to commands with the pre-processor). That worked but was a little hard to read. I do want to produce a graphical front end for the whole thing. That has yet to be done but I have gone to generating from an xml file that contains the specifications for the application. Whilst that seems long and wordy, its mostly tags and it would not be hard to write a front end graphical editor for it. That specification includes all the information required to build the application, so I wouldn't need to build a separate interface for compiling and linking. You'll get some idea from the following which is the start of a specification (for a working application):
Code: Select all
<SIXTH-SENSE>
<APPLICATION>
<APP-NAME>gtkdoc</APP-NAME>
<APP-LONG-NAME>Doctor Software</APP-LONG-NAME>
<APP-VERSION>0.0.2</APP-VERSION>
<MAIN-WIN-WIDTH>900</MAIN-WIN-WIDTH>
<MAIN-WIN-HEIGHT>500</MAIN-WIN-HEIGHT>
<INCLUDE-STANDARD-LIBRARIES>Y</INCLUDE-STANDARD-LIBRARIES>
<AW-INCLUSION-LIST>
<AW-INCLUSION>rapids.ch</AW-INCLUSION>
</AW-INCLUSION-LIST>
<MAIN-MENU>
<MENU-ITEM>
<MENU-NAME>File</MENU-NAME>
<MENU-OPTION-LIST>
<MENU-OPTION>
<MENU-OPTION-NAME>Exit</MENU-OPTION-NAME>
<MENU-OPTION-CODE>ProgExit()</MENU-OPTION-CODE>
</MENU-OPTION>
</MENU-OPTION-LIST>
</MENU-ITEM>
<MENU-ITEM>
<MENU-NAME>Patient</MENU-NAME>
<MENU-OPTION-LIST>
<MENU-OPTION>
<MENU-OPTION-NAME>By Name</MENU-OPTION-NAME>
<MENU-OPTION-CODE>obj_PatientList:SearchBySurname()</MENU-OPTION-CODE>
</MENU-OPTION>
<MENU-OPTION>
<MENU-OPTION-NAME>By Key</MENU-OPTION-NAME>
<MENU-OPTION-CODE>obj_Patient:SearchByKey()</MENU-OPTION-CODE>
</MENU-OPTION>
<MENU-OPTION>
<MENU-OPTION-NAME>File By Key</MENU-OPTION-NAME>
<MENU-OPTION-CODE>obj_PatientFile:SearchByKey()</MENU-OPTION-CODE>
</MENU-OPTION>
</MENU-OPTION-LIST>
</MENU-ITEM>
<MENU-ITEM>
<MENU-NAME>Doctor</MENU-NAME>
<MENU-OPTION-LIST>
<MENU-OPTION>
<MENU-OPTION-NAME>By Name</MENU-OPTION-NAME>
<MENU-OPTION-CODE>obj_DoctorList:SearchByName()</MENU-OPTION-CODE>
</MENU-OPTION>
<MENU-OPTION>
<MENU-OPTION-NAME>By Key</MENU-OPTION-NAME>
<MENU-OPTION-CODE>obj_Doctor:SearchByKey()</MENU-OPTION-CODE>
</MENU-OPTION>
</MENU-OPTION-LIST>
</MENU-ITEM>
<MENU-ITEM>
<MENU-NAME>Practice</MENU-NAME>
<MENU-OPTION-LIST>
<MENU-OPTION>
<MENU-OPTION-NAME>By PostCode</MENU-OPTION-NAME>
<MENU-OPTION-CODE>obj_MedicalPracticeList:SearchByPCode()</MENU-OPTION-CODE>
</MENU-OPTION>
<MENU-OPTION>
<MENU-OPTION-NAME>By Key</MENU-OPTION-NAME>
<MENU-OPTION-CODE>obj_MedicalPractice:SearchByKey()</MENU-OPTION-CODE>
</MENU-OPTION>
</MENU-OPTION-LIST>
</MENU-ITEM>
<MENU-ITEM>
<MENU-NAME>Help</MENU-NAME>
<MENU-OPTION-LIST>
<MENU-OPTION>
<MENU-OPTION-NAME>About</MENU-OPTION-NAME>
<MENU-OPTION-CODE>About()</MENU-OPTION-CODE>
</MENU-OPTION>
</MENU-OPTION-LIST>
</MENU-ITEM>
</MAIN-MENU>
<UTILITY-LIST>
<UTILITY>
<UTILITY-NAME>Locations</UTILITY-NAME>
<INSTANTIATE-UTILITY>Y</INSTANTIATE-UTILITY>
<UTILITY-CODE-LIST>
<UTILITY-CODE-LINE>obj_Locations:SetHome( GetEnv( 'HOME' ) + '/' )</UTILITY-CODE-LINE>
<UTILITY-CODE-LINE>SELECT 101</UTILITY-CODE-LINE>
<UTILITY-CODE-LINE>USE ( obj_Locations:str_Home + 'EMPHASIS' )</UTILITY-CODE-LINE>
<UTILITY-CODE-LINE>GOTO 1</UTILITY-CODE-LINE>
<UTILITY-CODE-LINE>str_IPAddress := AllTrim( IPADDRESS )</UTILITY-CODE-LINE>
<UTILITY-CODE-LINE>int_Port := PORT</UTILITY-CODE-LINE>
<UTILITY-CODE-LINE>SELECT 101</UTILITY-CODE-LINE>
<UTILITY-CODE-LINE>USE</UTILITY-CODE-LINE>
<UTILITY-CODE-LINE>str_IPAddress := '127.0.0.1'</UTILITY-CODE-LINE>
<UTILITY-CODE-LINE>? 'IP Address set to', str_IPAddress</UTILITY-CODE-LINE>
<UTILITY-CODE-LINE>? 'Server Port set to', int_Port</UTILITY-CODE-LINE>
</UTILITY-CODE-LIST>
</UTILITY>
<UTILITY>
<UTILITY-NAME>User</UTILITY-NAME>
<INSTANTIATE-UTILITY>Y</INSTANTIATE-UTILITY>
<UTILITY-CODE-LIST>
<UTILITY-CODE-LINE>obj_User:str_Key := "000000000000001"</UTILITY-CODE-LINE>
</UTILITY-CODE-LIST>
</UTILITY>
<UTILITY>
<UTILITY-NAME>SingleItem</UTILITY-NAME>
</UTILITY>
<UTILITY>
<UTILITY-NAME>ListScreen</UTILITY-NAME>
</UTILITY>
<UTILITY>
<UTILITY-NAME>ViewEditScreen</UTILITY-NAME>
</UTILITY>
<UTILITY>
<UTILITY-NAME>KeySearchScreen</UTILITY-NAME>
</UTILITY>
<UTILITY>
<UTILITY-NAME>AlphaSearchScreen</UTILITY-NAME>
</UTILITY>
<UTILITY>
<UTILITY-NAME>Screen</UTILITY-NAME>
</UTILITY>
<UTILITY>
<UTILITY-NAME>Query</UTILITY-NAME>
</UTILITY>
<UTILITY>
<UTILITY-NAME>Socket</UTILITY-NAME>
<INSTANTIATE-UTILITY>Y</INSTANTIATE-UTILITY>
<UTILITY-CODE-LIST>
<UTILITY-CODE-LINE>obj_Socket:SetIP( str_IPAddress )</UTILITY-CODE-LINE>
<UTILITY-CODE-LINE>obj_Socket:SetPort( int_Port )</UTILITY-CODE-LINE>
<UTILITY-CODE-LINE>obj_Query := obj_Socket:CreateQueryObject()</UTILITY-CODE-LINE>
</UTILITY-CODE-LIST>
</UTILITY>
</UTILITY-LIST>
<MODULE-LIST>
<MODULE>
<MODULE-NAME>Patient</MODULE-NAME>
<TABLE>
<ALIAS>PT</ALIAS>
<TABLE-NAME>PATIENT</TABLE-NAME>
</TABLE>
<LIST-CLASS>
<INSTANTIATE-LIST-CLASS>Y</INSTANTIATE-LIST-CLASS>
</LIST-CLASS>
<SINGLE-CLASS>
<INSTANTIATE-SINGLE-CLASS>Y</INSTANTIATE-SINGLE-CLASS>
</SINGLE-CLASS>
<VIEW-EDIT-SCREEN>
<VES-WIDTH>1000</VES-WIDTH>
<VES-HEIGHT>800</VES-HEIGHT>
<VES-FOCUS>entry_Surname</VES-FOCUS>
<VES-CODE>/home/bwana/ss/addedcode/ptveac.prg</VES-CODE>
<ADDITIONAL-VE-METHODS>
<VE-METHOD>
<VE-METHOD-NAME>SetTitle</VE-METHOD-NAME>
<VE-METHOD-PARAMETERS>str_Title, int_Gender</VE-METHOD-PARAMETERS>
<VE-METHOD-SOURCE>/home/bwana/ss/addedcode/pt_ve_settitle.prg</VE-METHOD-SOURCE>
<VE-METHOD-FROM-FILE>Y</VE-METHOD-FROM-FILE>
</VE-METHOD>
<VE-METHOD>
<VE-METHOD-NAME>SetSuburb</VE-METHOD-NAME>
<VE-METHOD-PARAMETERS>str_Suburb, str_PostCode</VE-METHOD-PARAMETERS>
<VE-METHOD-SOURCE>/home/bwana/ss/addedcode/pt_ve_setsuburb.prg</VE-METHOD-SOURCE>
<VE-METHOD-FROM-FILE>Y</VE-METHOD-FROM-FILE>
</VE-METHOD>
</ADDITIONAL-VE-METHODS>
<VE-ACTION-BUTTONS>
<VE-ACTION-BUTTON>
<VEAB-NAME>Files</VEAB-NAME>
<VEAB-LABEL>_Files</VEAB-LABEL>
<VEAB-RESPONSE-ID>901</VEAB-RESPONSE-ID>
<VEAB-EXEC-CODE>obj_PatientFileList:Fetch( ::obj_DataSource:str_Key )#obj_PatientFileList:Show()</VEAB-EXEC-CODE>
</VE-ACTION-BUTTON>
</VE-ACTION-BUTTONS>
</VIEW-EDIT-SCREEN>
<SEARCH-BY-SCREEN>
<SBS-NAME>Surname</SBS-NAME>
<SBS-PROMPT>Surname</SBS-PROMPT>
<SBS-CHARACTERS>32</SBS-CHARACTERS>
<SBS-ENTRY-WIDTH>240</SBS-ENTRY-WIDTH>
<SBS-DATA-FORMAT>U</SBS-DATA-FORMAT>
<SBS-EXACT-OPTION>Y</SBS-EXACT-OPTION>
</SEARCH-BY-SCREEN>
<PROPERTY-LIST>
<PROPERTY>
<VARIABLE>
<VARIABLE-NAME>Key</VARIABLE-NAME>
<VARIABLE-TYPE>P</VARIABLE-TYPE>
<VARIABLE-CHARACTERS>16</VARIABLE-CHARACTERS>
</VARIABLE>
<WIDGET>
<WIDGET-TYPE>E</WIDGET-TYPE>
<WIDGET-DATA-FORMAT>S</WIDGET-DATA-FORMAT>
<WIDGET-LEFT>110</WIDGET-LEFT>
<WIDGET-TOP>30</WIDGET-TOP>
<WIDGET-WIDTH>240</WIDGET-WIDTH>
<WIDGET-HEIGHT>25</WIDGET-HEIGHT>
<WIDGET-EDITABLE-WHEN>N</WIDGET-EDITABLE-WHEN>
</WIDGET>
<LABEL>
<LABEL-TEXT>Key</LABEL-TEXT>
<LABEL-LEFT>10</LABEL-LEFT>
<LABEL-TOP>30</LABEL-TOP>
<LABEL-WIDTH>90</LABEL-WIDTH>
<LABEL-HEIGHT>25</LABEL-HEIGHT>
</LABEL>
<COLUMN>
<COLUMN-TYPE>S</COLUMN-TYPE>
<COLUMN-NUMBER>0</COLUMN-NUMBER>
<COLUMN-HEADING>Key</COLUMN-HEADING>
</COLUMN>
<FIELD>
<FIELD-NAME>PT_KEY</FIELD-NAME>
</FIELD>
</PROPERTY>
<PROPERTY>
<VARIABLE>
<VARIABLE-NAME>Title</VARIABLE-NAME>
<VARIABLE-TYPE>S</VARIABLE-TYPE>
<VARIABLE-CHARACTERS>8</VARIABLE-CHARACTERS>
</VARIABLE>
<WIDGET>
<WIDGET-TYPE>E</WIDGET-TYPE>
<WIDGET-DATA-FORMAT>S</WIDGET-DATA-FORMAT>
<WIDGET-LEFT>110</WIDGET-LEFT>
<WIDGET-TOP>60</WIDGET-TOP>
<WIDGET-WIDTH>90</WIDGET-WIDTH>
<WIDGET-HEIGHT>25</WIDGET-HEIGHT>
<WIDGET-EDITABLE-WHEN>E</WIDGET-EDITABLE-WHEN>
</WIDGET>
<LABEL>
<LABEL-TEXT>Title</LABEL-TEXT>
<LABEL-LEFT>10</LABEL-LEFT>
<LABEL-TOP>60</LABEL-TOP>
<LABEL-WIDTH>90</LABEL-WIDTH>
<LABEL-HEIGHT>25</LABEL-HEIGHT>
</LABEL>
<FIELD>
<FIELD-NAME>PT_NMTITLE</FIELD-NAME>
</FIELD>
</PROPERTY>
<PROPERTY>
<VARIABLE>
<VARIABLE-NAME>GivenNames</VARIABLE-NAME>
<VARIABLE-TYPE>S</VARIABLE-TYPE>
<VARIABLE-CHARACTERS>32</VARIABLE-CHARACTERS>
</VARIABLE>
<WIDGET>
<WIDGET-TYPE>E</WIDGET-TYPE>
<WIDGET-DATA-FORMAT>S</WIDGET-DATA-FORMAT>
<WIDGET-LEFT>110</WIDGET-LEFT>
<WIDGET-TOP>90</WIDGET-TOP>
<WIDGET-WIDTH>320</WIDGET-WIDTH>
<WIDGET-HEIGHT>25</WIDGET-HEIGHT>
<WIDGET-EDITABLE-WHEN>E</WIDGET-EDITABLE-WHEN>
</WIDGET>
<LABEL>
<LABEL-TEXT>Given Names</LABEL-TEXT>
<LABEL-LEFT>10</LABEL-LEFT>
<LABEL-TOP>90</LABEL-TOP>
<LABEL-WIDTH>90</LABEL-WIDTH>
<LABEL-HEIGHT>25</LABEL-HEIGHT>
</LABEL>
<COLUMN>
<COLUMN-TYPE>S</COLUMN-TYPE>
<COLUMN-NUMBER>2</COLUMN-NUMBER>
<COLUMN-HEADING>Given Names</COLUMN-HEADING>
</COLUMN>
<FIELD>
<FIELD-NAME>PT_NMGIVEN</FIELD-NAME>
</FIELD>
</PROPERTY>
<PROPERTY>
<VARIABLE>
<VARIABLE-NAME>Surname</VARIABLE-NAME>
<VARIABLE-TYPE>S</VARIABLE-TYPE>
<VARIABLE-CHARACTERS>32</VARIABLE-CHARACTERS>
</VARIABLE>
<WIDGET>
<WIDGET-TYPE>E</WIDGET-TYPE>
<WIDGET-DATA-FORMAT>U</WIDGET-DATA-FORMAT>
<WIDGET-LEFT>110</WIDGET-LEFT>
<WIDGET-TOP>120</WIDGET-TOP>
<WIDGET-WIDTH>320</WIDGET-WIDTH>
<WIDGET-HEIGHT>25</WIDGET-HEIGHT>
<WIDGET-EDITABLE-WHEN>E</WIDGET-EDITABLE-WHEN>
</WIDGET>
<LABEL>
<LABEL-TEXT>Surname</LABEL-TEXT>
<LABEL-LEFT>10</LABEL-LEFT>
<LABEL-TOP>120</LABEL-TOP>
<LABEL-WIDTH>90</LABEL-WIDTH>
<LABEL-HEIGHT>25</LABEL-HEIGHT>
</LABEL>
<COLUMN>
<COLUMN-TYPE>S</COLUMN-TYPE>
<COLUMN-NUMBER>1</COLUMN-NUMBER>
<COLUMN-HEADING>Surname</COLUMN-HEADING>
</COLUMN>
<FIELD>
<FIELD-NAME>PT_NMFAMLY</FIELD-NAME>
</FIELD>
</PROPERTY>
Re: Automating Compile and Link
Posted: Mon Oct 05, 2009 3:29 am
by xProgrammer
Hi Antonio
Current Structure of Compile and LInk back end is:
Class SSFile => encapsulates a file and its attributes, especially date and time Updated
Class SSPRGFile => derived from SSFile. Adds behaviour specific to .prg files, mainly extension
Class SSCFile => derived from SSFile. Adds behaviour specific to .c files, mainly extension
Class SSOBJFile => derived from SSFile. Adds behaviour specific to .obj files, mainly extension
Class SSPRGComponent => contains a .prg, .c and .obj file and understands status (that is does this component need to be recompiled), and can compile it
Class SSApplication (which already existed) will need extension, but it already knows about the required PRG components (both the ones it generates and existing ones) and any required libraries to be linked in. It need code to control the above process including forced rebuild from scratch and how to link the object code.
Regards
Doug (xProgrammer)
Re: Automating Compile and Link
Posted: Mon Oct 05, 2009 12:32 pm
by xProgrammer
Hi Antonio
Whilst the compile and link code is not nice and clean as yet, the generator can now take an application definition (as an xml file), generate the .prg code, compile that code and link it to produce an executable and run the executable it has produced all in a single process. I have code to work out which files need recompilation but haven't as yet made that active - clearly when I do I will also need a switch to "force" a total rebuild.
Regards
Doug (xProgrammer)
Re: Automating Compile and Link
Posted: Sun Nov 15, 2009 4:22 pm
by Antonio Linares
Doug,
it would be great of you could post some screenshots of what you are doing, how the apps look, etc. Thanks!