Files
harbour-core/harbour/contrib/make.hb
Viktor Szakats 3fb65e7924 2013-02-18 14:48 UTC+0100 Viktor Szakats (harbour syenar.net)
* utils/hbmk2/hbmk2.*.po
  * utils/hbmk2/hbmk2.prg
    + added '-hb30' option and '{hb30}' filter macro to allow
      reverting back to Harbour 3.0.0
    + added provisions for merging 'hblang' and 'hbcpage'
      core libs into new 'hbnat' lib
    + SETCURSOR() and SETCOLOR() references will now also
      trigger full screen CUI mode in hbrun scripts
    + documented the fact that GTCGI is default GT for scripts
      and that it's switched to another one (and which) when
      CUI mode script is detected
    + marked all information in help with '[*]' which shows
      host platform dependent, dynamic data (f.e. systems paths)
    + hbmk.hbc will now be searched for under user's home
      directory on non-*nix, too
    + added '-find' special hbmk2 option for finding Harbour functions.
      It will lookup any strings passed as command line arguments
      and display in which library they can be found. It will
      also do the lookup in packages not currently installed.
      Replaces similar 'hbrun bin/find' functionality, but now
      uses existing code inside hbmk2. The new implementation
      also supports wildcards.
      Example:
         hbmk2 -find wapi_*string ntos wild
    ! documented that hbstart.hb is first searched for in
      current working directory
    ! ${hb_ver} and ${hb_verstr} macros now change their value
      in compatibility modes (-hb10, -hb20, -hb30, -xhb)
    + -longhelpmd output will now not contain installation
      specific (and potentially sensitive) data: home directory,
      hbmk2 directory, only generic replacement terms
    + version= directive help text got a mention of its default
      value (it was so far only mentioned next to HBMK_HAS_<hbcname>
      envvar)
    + documented exit codes in help text
    * minor tweaks to some help lines
    * cleanup for Markdown formatting internals
    * plugin callback variable "nErrorLevel" renamed to "nExitCode"
      [INCOMPATIBLE]
    * exit code changed to value 6 from 1 when hbrun script has
      a compile error [INCOMPATIBLE]
    + use core hb_DirSepToOS() where possible
    - deleted hbmk2 plugin API function hbmk_PathSepToSelf()
      Use core hb_DirSepToOS() instead. [INCOMPATIBLE]
    + added '-exitstr' hbmk2 option which will display the exit result
      in textual format

  * contrib/hbpre.hbm
  * contrib/make.hb
    % use -exitstr hbmk2 option instead of rolling a local copy
      of possible result strings

  * src/pp/ppcore.c
    + generate '\a' '\f' '\v' escape chars

  - bin/find.hb
  * config/postinst.hb
  * package/harbour.spec
    - deleted find.hb for 'hbrun bin/find' functionality.
      Replaced by 'hbmk2 -find' option.

  * src/rtl/Makefile
  - src/rtl/strxchg.c
  + src/rtl/strrepl.c
  * src/rtl/tget.prg
  * utils/hbmk2/hbmk2.prg
  * include/harbour.hbx
  * ChangeLog.txt
    * renamed HB_STRXCHG() to HB_STRREPLACE(), according to:
         https://groups.google.com/d/topic/harbour-devel/vSzlAkv6h9Y/discussion
    * updated function skeleton in ChangeLog and C source
      (also with new hash parameter)

  * contrib/hbsqlit3/hbsqlit3.hbp
  * contrib/hbsqlit3/hbsqlit3.hbx
  + contrib/hbsqlit3/errstr.prg
    + hb_sqlite3_errstr_short( <nError> ) -> <cError>

  * contrib/hbsqlit3/tests/authoriz.prg
  * contrib/hbsqlit3/tests/backup.prg
  * contrib/hbsqlit3/tests/hooks.prg
    % use hb_sqlite3_errstr_short() instead of implementing
      it locally in each example
    % use sqlite3_errstr() API to get long error strings instead
      of reimplementing it locally
    % minor opt

  * contrib/hbsqlit3/hbsqlit3.hbp
  - contrib/hbsqlit3/hdbcsqlt.prg
  + contrib/hbsqlit3/hdbc.prg
    * renamed

  * contrib/hbhpdf/errstr.prg
  * contrib/hbmzip/mziperr.prg
    ! indenting

  * contrib/hbtip/tests/tiptest.prg
    * leave color
2013-02-18 13:50:13 +00:00

766 lines
23 KiB
Plaintext
Executable File

#!/usr/bin/hbrun --hb:gtcgi
/*
* $Id$
*/
/*
* Harbour Project source code:
* Package build orchestrator script
*
* Copyright 2010 Viktor Szakats (harbour syenar.net)
* www - http://harbour-project.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA (or visit
* their web site at http://www.gnu.org/).
*
*/
#pragma warninglevel=3
#pragma -km+
#pragma -ko+
#include "directry.ch"
#define _ACT_INC_CLEAN 1
#define _ACT_INC 2
#define _ACT_INC_INST 3
#define _ACT_INC_REBUILD 4
#define _ACT_INC_REBUILD_INST 5
STATIC sc_hActions := { ;
_ACT_INC_CLEAN => "clean", ;
_ACT_INC => "build", ;
_ACT_INC_INST => "build and install", ;
_ACT_INC_REBUILD => "rebuild", ;
_ACT_INC_REBUILD_INST => "rebuild and install" }
STATIC s_cBase
STATIC s_cHome
STATIC s_cRoot
STATIC s_cBinDir
STATIC s_cReBase
PROCEDURE Main( ... )
LOCAL hProjectList
LOCAL aParams
hb_cdpSelect( "UTF8EX" )
s_cBase := ""
s_cReBase := ""
IF Empty( GetEnv( "HB_HOST_BIN_DIR" ) )
s_cHome := StrTran( hb_DirBase(), hb_ps(), "/" )
s_cRoot := s_cHome + "../"
ELSE
s_cHome := ""
s_cRoot := "../"
ENDIF
#if defined( __HBSCRIPT__HBSHELL )
s_cBinDir := hbshell_DirBase()
#else
s_cBinDir := hb_DirBase()
#endif
/* For *nixes */
s_cBinDir := hb_PathNormalize( s_cBinDir )
/* Load list of projects */
hProjectList := { => }
hb_HKeepOrder( hProjectList, .T. )
LoadProjectListFromFile( hProjectList, s_cHome + "hbplist" )
LoadProjectListFromString( hProjectList, GetEnv( "HB_BUILD_ADDONS" ) )
aParams := hb_AParams()
IF AScanL( aParams, "verbose" ) > 0
hb_SetEnv( "HB_BUILD_VERBOSE", "yes" )
ENDIF
/* Build */
IF Empty( GetEnv( "HB_HOST_BIN_DIR" ) )
Standalone( aParams, hProjectList )
ELSE
GNUMake( aParams, hProjectList )
ENDIF
RETURN
/* Workflow translation for standalone operation:
GNU Make parameter nAction hbmk2 options
-- -------------- -------------- ---------------------- -------------------------
#1 clean clean _ACT_INC_CLEAN -inc -clean
#2 _ACT_INC -inc
#3 clean all clean all _ACT_INC_REBUILD -inc -rebuildall
#4 install install _ACT_INC_INST -inc -instpath=
#5 clean install clean install _ACT_INC_REBUILD_INST -inc -rebuildall -instpath=
*/
PROCEDURE Standalone( aParams, hProjectList )
LOCAL hProjectReqList
LOCAL cOptionsUser
LOCAL nAction
LOCAL tmp
LOCAL tmp1
LOCAL lCustom
/* Processing cmdline options */
DO CASE
CASE AScanL( aParams, "clean" ) > 0 .AND. ;
AScanL( aParams, "all" ) > 0 .AND. ;
AScanL( aParams, "all" ) > AScanL( aParams, "clean" )
nAction := _ACT_INC_REBUILD
CASE AScanL( aParams, "rebuild" ) > 0
nAction := _ACT_INC_REBUILD
CASE AScanL( aParams, "clean" ) > 0 .AND. ;
AScanL( aParams, "install" ) > 0 .AND. ;
AScanL( aParams, "install" ) > AScanL( aParams, "clean" )
nAction := _ACT_INC_REBUILD_INST
CASE AScanL( aParams, "clean" ) > 0
nAction := _ACT_INC_CLEAN
CASE AScanL( aParams, "install" ) > 0
nAction := _ACT_INC_INST
OTHERWISE
nAction := _ACT_INC
ENDCASE
/* Processing user options */
cOptionsUser := ""
lCustom := .F.
FOR EACH tmp IN aParams
IF !( Lower( tmp ) == "install" ) .AND. ;
!( Lower( tmp ) == "clean" ) .AND. ;
!( Lower( tmp ) == "all" ) .AND. ;
!( Lower( tmp ) == "first" ) .AND. ;
!( Lower( tmp ) == "rebuild" ) .AND. ;
!( Lower( tmp ) == "verbose" )
cOptionsUser += " " + tmp
/* If anything else is passed than options or GNU Make keywords,
consider it a custom project build, f.e. in tests */
IF !( Left( tmp, 1 ) == "-" )
lCustom := .T.
ENDIF
ENDIF
NEXT
/* Assemble list of primary targets (registered projects in current directory) */
hProjectReqList := { => }
hb_HKeepOrder( hProjectReqList, .T. )
IF ! lCustom
/* Find out which projects are in current dir, these will be our primary targets */
FOR EACH tmp IN hProjectList
tmp1 := hb_ps() + hb_FNameDir( hb_DirSepToOS( tmp:__enumKey() ) )
IF tmp1 == Right( hb_cwd(), Len( tmp1 ) ) /* Not ultimate solution */
hProjectReqList[ tmp:__enumKey() ] := tmp:__enumKey()
s_cReBase := SubStr( tmp1, 2 )
ENDIF
NEXT
IF Empty( hProjectReqList )
lCustom := .T.
ELSE
OutStd( hb_StrFormat( "! Package %1$s... %2$d project(s)", sc_hActions[ nAction ], Len( hProjectReqList ) ) + hb_eol() )
ENDIF
ENDIF
IF lCustom
mk_hb_processRun( s_cBinDir + "hbmk2" + cOptionsUser )
RETURN
ENDIF
/* Start building */
build_projects( nAction, hProjectList, hProjectReqList, cOptionsUser, .T. )
RETURN
/* Workflow translation from GNU Make to hbmk2:
GNU Make parameter HB_MAKECMDGOALS nAction hbmk2 options
-- -------------- ---------- ---------------- ---------------------- -------------------------
#1 clean clean clean _ACT_INC_CLEAN -inc -clean
#2 all _ACT_INC -inc
#3 install install install _ACT_INC_INST -inc -instpath=
#4 clean all clean clean all _ACT_INC_CLEAN -inc -clean
first clean all _ACT_INC_REBUILD -inc -rebuildall
#5 clean install clean clean install _ACT_INC_CLEAN -inc -clean
install clean install _ACT_INC_REBUILD_INST -inc -rebuildall -instpath=
#6 install clean install install clean _ACT_INC_INST -inc -instpath=
clean install clean _ACT_INC_CLEAN -inc -clean
*/
PROCEDURE GNUMake( aParams, hProjectList )
LOCAL cProject
LOCAL hProjectReqList
LOCAL cFilter
LOCAL aFilter
LOCAL lFilterNegative
LOCAL aGNUMakeParams
LOCAL nAction
LOCAL tmp
/* Check if the requirements are met and if we have anything to do */
IF Empty( GetEnv( "HB_PLATFORM" ) ) .OR. ;
Empty( GetEnv( "HB_COMPILER" ) ) .OR. ;
Empty( GetEnv( "HB_HOST_BIN_DIR" ) )
ErrorLevel( 9 )
RETURN
ENDIF
/* Determine the mode of operation */
aGNUMakeParams := hb_ATokens( Lower( GetEnv( "HB_MAKECMDGOALS" ) ) )
DO CASE
CASE AScanL( aParams, "clean" ) > 0
IF AScanL( aGNUMakeParams, "clean" ) > 0 .AND. ;
AScanL( aGNUMakeParams, "install" ) > 0 .AND. ;
AScanL( aGNUMakeParams, "install" ) > AScanL( aGNUMakeParams, "clean" )
nAction := _ACT_INC_CLEAN
ELSE
nAction := _ACT_INC_CLEAN
ENDIF
CASE AScanL( aParams, "install" ) > 0
IF AScanL( aGNUMakeParams, "clean" ) > 0 .AND. ;
AScanL( aGNUMakeParams, "install" ) > 0 .AND. ;
AScanL( aGNUMakeParams, "install" ) > AScanL( aGNUMakeParams, "clean" )
/* Use rebuild mode. This is needed because the clean phase
might not have been called previously by GNU Make, f.e.
because hbrun or hbmk2 wasn't available. -rebuildall is
costless, so we do it to make sure to build cleanly.
[vszakats] */
nAction := _ACT_INC_REBUILD_INST
ELSE
nAction := _ACT_INC_INST
ENDIF
CASE AScanL( aParams, "first" ) > 0
IF AScanL( aGNUMakeParams, "clean" ) > 0 .AND. ;
AScanL( aGNUMakeParams, "all" ) > 0 .AND. ;
AScanL( aGNUMakeParams, "all" ) > AScanL( aGNUMakeParams, "clean" )
nAction := _ACT_INC_REBUILD
ELSE
nAction := _ACT_INC
ENDIF
CASE AScanL( aParams, "rebuild" ) > 0
nAction := _ACT_INC_REBUILD
OTHERWISE
nAction := _ACT_INC
ENDCASE
/* Assemble list of projects to be built */
cFilter := GetEnv( "HB_BUILD_CONTRIBS" )
IF ! Empty( cFilter )
OutStd( "! HB_BUILD_CONTRIBS: " + cFilter + hb_eol() )
ENDIF
IF cFilter == "no"
RETURN
ENDIF
aFilter := iif( Empty( cFilter ), {}, hb_ATokens( cFilter,, .T. ) )
IF Len( aFilter ) >= 1 .AND. aFilter[ 1 ] == "no"
hb_ADel( aFilter, 1, .T. )
lFilterNegative := .T.
ELSE
lFilterNegative := .F.
ENDIF
hProjectReqList := { => }
hb_HKeepOrder( hProjectReqList, .T. )
FOR EACH tmp IN hProjectList
hProjectReqList[ tmp:__enumKey() ] := tmp:__enumKey()
NEXT
IF ! Empty( aFilter )
IF ! lFilterNegative
hProjectReqList := { => }
ENDIF
FOR EACH cProject IN aFilter
FOR EACH tmp IN hProjectList
IF hb_FileMatch( hb_DirSepToOS( cProject ), hb_DirSepToOS( tmp:__enumKey() ) ) .OR. ;
hb_FileMatch( hb_DirSepToOS( cProject ), hb_DirSepDel( hb_FNameDir( hb_DirSepToOS( tmp:__enumKey() ) ) ) )
IF lFilterNegative
IF tmp:__enumKey() $ hProjectReqList
hb_HDel( hProjectReqList, tmp:__enumKey() )
ENDIF
ELSE
hProjectReqList[ tmp:__enumKey() ] := tmp:__enumKey()
ENDIF
ENDIF
NEXT
NEXT
ENDIF
IF Empty( hProjectReqList )
RETURN
ENDIF
/* Clearing envvars that may interact with hbmk2 */
/* Saving original install dirs to our own variables */
hb_SetEnv( "_HB_INSTALL_BIN", GetEnv( "HB_INSTALL_BIN" ) )
hb_SetEnv( "_HB_INSTALL_LIB", GetEnv( "HB_INSTALL_LIB" ) )
hb_SetEnv( "_HB_INSTALL_DYN", GetEnv( "HB_INSTALL_DYN" ) )
hb_SetEnv( "_HB_INSTALL_INC", GetEnv( "HB_INSTALL_INC" ) )
hb_SetEnv( "_HB_INSTALL_MAN", GetEnv( "HB_INSTALL_MAN" ) )
hb_SetEnv( "_HB_INSTALL_ETC", GetEnv( "HB_INSTALL_ETC" ) )
hb_SetEnv( "_HB_INSTALL_CONTRIB", GetEnv( "HB_INSTALL_CONTRIB" ) )
/* Override hbmk2 autodetection. WARNING: Must be in sync with global.mk logic */
hb_SetEnv( "HB_INSTALL_PREFIX", s_cRoot )
hb_SetEnv( "HB_INSTALL_BIN", s_cRoot + "bin/" + GetEnv( "HB_PLATFORM" ) + "/" + GetEnv( "HB_COMPILER" ) + GetEnv( "HB_BUILD_NAME" ) )
hb_SetEnv( "HB_INSTALL_LIB", s_cRoot + "lib/" + GetEnv( "HB_PLATFORM" ) + "/" + GetEnv( "HB_COMPILER" ) + GetEnv( "HB_BUILD_NAME" ) )
hb_SetEnv( "HB_INSTALL_DYN" )
hb_SetEnv( "HB_INSTALL_INC", s_cRoot + "include" )
/* Start building */
OutStd( hb_StrFormat( "! Started package %1$s...", sc_hActions[ nAction ] ) + hb_eol() )
build_projects( nAction, hProjectList, hProjectReqList, "", .F. )
OutStd( hb_StrFormat( "! Finished package %1$s...", sc_hActions[ nAction ] ) + hb_eol() )
RETURN
STATIC PROCEDURE build_projects( nAction, hProjectList, hProjectReqList, cOptionsUser, lStdAlone )
LOCAL aPairList
LOCAL aSortedList
LOCAL cOptions
LOCAL lInstall
LOCAL cMakeFlags
LOCAL cProject
LOCAL cProjectPath
LOCAL lPrimary
LOCAL lContainer
LOCAL cDynSuffix
LOCAL nErrorLevel
/* Signal that we're doing a Harbour build */
hb_SetEnv( "_HB_BUILD_", "yes" )
/* Preprocessing */
IF Len( hProjectReqList ) > 1
OutStd( hb_StrFormat( "! Calculating build order for %1$d projects...", Len( hProjectReqList ) ) + hb_eol() )
ENDIF
aPairList := {}
FOR EACH cProject IN hProjectReqList
call_hbmk2_hbinfo( s_cBase + s_cHome + cProject, hProjectList[ cProject ] )
DeptLinesToDeptPairList( aPairList, cProject, hProjectList[ cProject ][ "aDept" ] )
NEXT
aSortedList := TopoSort( aPairList )
/* Add referenced project not present in our list and featuring an .hbp file */
FOR EACH cProject IN aSortedList
IF !( cProject $ hProjectList )
IF hb_FileExists( s_cBase + s_cHome + cProject )
AddProject( hProjectList, cProject )
call_hbmk2_hbinfo( s_cBase + s_cHome + cProject, hProjectList[ cProject ] )
hProjectList[ cProject ][ "lFromContainer" ] := NIL
ENDIF
ENDIF
NEXT
/* Load project information for dependencies too
(we need "cType" to decide about dynamic build) */
IF GetEnv( "HB_BUILD_CONTRIB_DYN" ) == "yes"
FOR EACH cProject IN aSortedList
IF !( cProject $ hProjectReqList ) .AND. ;
cProject $ hProjectList .AND. ;
!( "lChecked" $ hProjectList[ cProject ] )
call_hbmk2_hbinfo( s_cBase + s_cHome + cProject, hProjectList[ cProject ] )
ENDIF
NEXT
ENDIF
/* Convert action to hbmk2 options */
cOptions := " -inc"
IF nAction == _ACT_INC_CLEAN
cOptions += " -clean"
ELSEIF nAction == _ACT_INC_REBUILD .OR. ;
nAction == _ACT_INC_REBUILD_INST
cOptions += " -rebuildall"
ENDIF
cMakeFlags := GetEnv( "MAKEFLAGS" )
IF " -j " $ " " + cMakeFlags + " "
/* GNU Make uses job server to limit number of concurrent operations
* We cannot read it from MAKEFLAGS so I set it to arbitrary value: 8
*/
cOptions += " -jobs=8"
ENDIF
lInstall := nAction == _ACT_INC_INST .OR. ;
nAction == _ACT_INC_REBUILD_INST
hb_SetEnv( iif( lStdAlone, "_HB_BUILD_INSTALL_STDALONE", "_HB_BUILD_INSTALL" ), iif( lInstall, "yes", NIL ) )
/* Build the dependencies and primary targets in sorted order */
FOR EACH cProject IN aSortedList DESCEND
IF cProject $ hProjectList
cProjectPath := s_cBase + s_cHome + cProject
lPrimary := cProject $ hProjectReqList
lContainer := "lFromContainer" $ hProjectList[ cProject ]
IF ( nErrorLevel := call_hbmk2( cProjectPath, iif( lPrimary .OR. lContainer, iif( lContainer, cOptions, cOptions + cOptionsUser ), " -inc" ) + ;
iif( ( lPrimary .OR. lContainer ) .AND. ;
hProjectList[ cProject ][ "cType" ] $ "hblib|hbdyn" .AND. ;
GetEnv( "HB_REBUILD_EXTERN" ) == "yes", " -hbx=" + hb_FNameExtSet( cProjectPath, ".hbx" ), "" ), NIL ) ) == 0
/* Build dynamic lib */
IF GetEnv( "HB_BUILD_CONTRIB_DYN" ) == "yes" .AND. hProjectList[ cProject ][ "cType" ] == "hblib"
/* Is this a platform where import libs are used? */
IF "|" + hProjectList[ cProject ][ "cPlatform" ] + "|" $ "|win|dos|os2|"
IF Empty( hProjectList[ cProject ][ "cDynSuffix" ] )
cDynSuffix := "_dll"
ELSE
cDynSuffix := hProjectList[ cProject ][ "cDynSuffix" ]
ENDIF
ELSE
cDynSuffix := hb_libExt()
ENDIF
call_hbmk2( cProjectPath, iif( lPrimary .OR. lContainer, iif( lContainer, cOptions, cOptions + cOptionsUser ), " -inc" ), cDynSuffix )
ENDIF
IF lPrimary .OR. lContainer
/* Compile documentation */
IF lInstall
mk_hbd( hb_FNameDir( hb_DirSepToOS( cProjectPath ) ) )
ENDIF
ENDIF
ELSE
/* Ignore certain non-fatal hbmk2 return values */
IF nErrorLevel != 10 .AND. ;
nErrorLevel != 20 .AND. ;
nErrorLevel != 50
ErrorLevel( nErrorLevel )
EXIT
ENDIF
ENDIF
ENDIF
NEXT
RETURN
STATIC FUNCTION call_hbmk2_hbinfo( cProjectPath, hProject )
LOCAL cStdOut
LOCAL cDir
LOCAL cName
LOCAL tmp
LOCAL hInfo
LOCAL nErrorLevel
hProject[ "cType" ] := ""
hProject[ "aDept" ] := {}
hProject[ "lChecked" ] := NIL
IF ( nErrorLevel := call_hbmk2( cProjectPath, " --hbinfo", NIL,, @cStdOut ) ) == 0
hb_jsonDecode( cStdOut, @hInfo )
hProject[ "cType" ] := hbmk2_hbinfo_getitem( hInfo, "targettype" )
hProject[ "cOutputName" ] := hbmk2_hbinfo_getitem( hInfo, "outputname" )
hProject[ "cDynSuffix" ] := hbmk2_hbinfo_getitem( hInfo, "dynsuffix" )
hProject[ "cPlatform" ] := hbmk2_hbinfo_getitem( hInfo, "platform" )
FOR EACH tmp IN hb_ATokens( hbmk2_hbinfo_getitem( hInfo, "hbctree" ), Chr( 10 ) )
IF ! Empty( tmp )
hb_FNameSplit( LTrim( tmp ), @cDir, @cName )
#ifdef __PLATFORM__DOS
/* Ignore long filenames on MS-DOS hosts */
IF Len( cName ) > 8
LOOP
ENDIF
#endif
AAdd( hProject[ "aDept" ], { "nDepth" => Len( tmp ) - Len( LTrim( tmp ) ), ;
"cFileName_HBP" => StrTran( hb_PathNormalize( hb_PathJoin( s_cRebase, hb_FNameExtSet( hb_DirSepToOS( LTrim( tmp ) ), ".hbp" ) ) ), "\", "/" ) } )
ENDIF
NEXT
ENDIF
RETURN nErrorLevel
STATIC FUNCTION hbmk2_hbinfo_getitem( hInfo, cItem )
RETURN iif( HB_ISHASH( hInfo ), hb_HGetDef( hInfo, cItem, "" ), "" )
STATIC FUNCTION call_hbmk2( cProjectPath, cOptionsPre, cDynSuffix, cStdErr, cStdOut )
LOCAL nErrorLevel
LOCAL cOptionsLibDyn := ""
LOCAL cCommand
/* Making sure that user settings do not interfere with the std build process. */
hb_SetEnv( "HBMK_OPTIONS" )
hb_SetEnv( "HARBOUR" )
hb_SetEnv( "HARBOURCMD" )
hb_SetEnv( "CLIPPER" )
hb_SetEnv( "CLIPPERCMD" )
IF cDynSuffix != NIL
hb_SetEnv( "_HB_DYNSUFF", cDynSuffix ) /* Request dll version of Harbour contrib dependencies (the implibs) to be linked (experimental) */
cOptionsPre += " -hbdyn"
IF hb_FileExists( hb_FNameExtSet( cProjectPath, ".hbc" ) )
cOptionsLibDyn += " " + hb_FNameExtSet( cProjectPath, ".hbc" )
ENDIF
ELSE
hb_SetEnv( "_HB_DYNSUFF" )
ENDIF
hb_SetEnv( "_HB_CONTRIB_SUBDIR", hb_FNameDir( hb_DirSepToOS( cProjectPath ) ) )
cCommand := s_cBinDir + "hbmk2" + ;
" -quiet -width=0 -autohbm-" + ;
" @" + StrTran( s_cHome + "hbpre", "\", "/" ) + ;
cOptionsPre + ;
" " + StrTran( cProjectPath, "\", "/" ) + ;
" @" + StrTran( s_cHome, "\", "/" ) + "hbpost" + ;
cOptionsLibDyn
IF PCount() >= 4
nErrorLevel := hb_processRun( cCommand,, @cStdOut, @cStdErr )
ELSE
nErrorLevel := mk_hb_processRun( cCommand )
ENDIF
RETURN nErrorLevel
STATIC FUNCTION mk_hb_processRun( cCommand, ... )
OutStd( cCommand + hb_eol() )
RETURN hb_processRun( cCommand, ... )
STATIC FUNCTION mk_hbd( cDir )
LOCAL cName
LOCAL cDocDir
LOCAL tmp
LOCAL aErrMsg
LOCAL aEntry
IF ! Empty( cDocDir := GetEnv( "HB_INSTALL_DOC" ) ) .AND. ! cDocDir == "no"
cName := DirGetName( cDir )
IF Empty( cName )
cName := "harbour"
ENDIF
aErrMsg := {}
aEntry := __hbdoc_LoadDir( cDir, cName, aErrMsg )
FOR EACH tmp IN aErrMsg
OutErr( hb_StrFormat( "! %1$s", tmp ) + hb_eol() )
NEXT
IF ! Empty( aEntry )
cName := hb_DirSepToOS( cDocDir ) + hb_ps() + cName + ".hbd"
IF __hbdoc_SaveHBD( cName, aEntry )
OutStd( "! Compiled documentation: " + cName + " <= " + cDir + hb_eol() )
RETURN .T.
ELSE
OutErr( hb_StrFormat( "! Error: Saving '%1$s'", cName ) + hb_eol() )
ENDIF
ENDIF
ENDIF
RETURN .F.
STATIC FUNCTION AScanL( aArray, cString )
RETURN AScan( aArray, {| tmp | Lower( tmp ) == cString } )
STATIC FUNCTION DirGetName( cDir )
LOCAL cName
cDir := hb_DirSepDel( cDir )
hb_FNameSplit( cDir,, @cName )
IF Empty( cName ) .OR. cName == "." .OR. cName == ".."
RETURN ""
ENDIF
RETURN cName
/* Convert indented list of line to tree / list of parent-child pairs */
STATIC PROCEDURE DeptLinesToDeptPairList( aPairList, cParent, aFlatTree )
LOCAL hFlatTreeElement
LOCAL hNode, hNewNode, tmp
LOCAL nLevel, nDepth
AddDeptPair( aPairList, "", cParent )
hNode := { "child" => {}, "name" => cParent, "parent" => NIL }
nLevel := 0
FOR EACH hFlatTreeElement IN aFlatTree
/* Min() protects against jumping more than one level down in one step */
nDepth := Min( hFlatTreeElement[ "nDepth" ], nLevel + 1 )
hNewNode := { "child" => {}, "name" => hFlatTreeElement[ "cFileName_HBP" ], "cargo" => hFlatTreeElement }
IF nDepth > nLevel
hNode := ATail( hNode[ "child" ] )
ELSEIF nDepth < nLevel
FOR tmp := nDepth + 1 TO nLevel
hNode := hNode[ "parent" ]
NEXT
ENDIF
hNewNode[ "parent" ] := hNode
AAdd( hNode[ "child" ], hNewNode )
nLevel := nDepth
AddDeptPair( aPairList, hNewNode[ "parent" ][ "name" ], hNewNode[ "name" ] )
NEXT
RETURN
/* Add parent-child dependency to the list */
STATIC PROCEDURE AddDeptPair( aPairList, cParent, cChild )
IF AScan( aPairList, {| tmp | tmp[ 1 ] == cParent .AND. tmp[ 2 ] == cChild } ) == 0
AAdd( aPairList, { cParent, cChild } )
ENDIF
RETURN
/* Topological sort of the dependency graph */
STATIC FUNCTION TopoSort( aEdgeList )
LOCAL aList := {}
LOCAL hTopNodes := { => }
LOCAL n, m
LOCAL tmp
hb_HKeepOrder( hTopNodes, .T. )
FOR EACH n IN aEdgeList
IF AScan( aEdgeList, {| tmp | tmp[ 2 ] == n[ 1 ] } ) == 0
hTopNodes[ n[ 1 ] ] := NIL
ENDIF
NEXT
DO WHILE ! Empty( hTopNodes )
n := hb_HKeyAt( hTopNodes, 1 )
hb_HDelAt( hTopNodes, 1 )
IF ! Empty( n )
AAdd( aList, n )
ENDIF
FOR EACH tmp IN aEdgeList
IF tmp[ 1 ] == n
m := tmp[ 2 ]
tmp[ 1 ] := tmp[ 2 ] := NIL /* set to invalid value. TOOPT: Delete this member from list */
IF AScan( aEdgeList, {| tmp | tmp[ 2 ] == m } ) == 0
hTopNodes[ m ] := NIL
ENDIF
ENDIF
NEXT
ENDDO
FOR EACH tmp IN aEdgeList
IF !( tmp[ 1 ] == NIL .AND. tmp[ 2 ] == NIL )
OutStd( hb_StrFormat( "! Warning: Circular reference in dependency tree (%1$s - %2$s)", tmp[ 1 ], tmp[ 2 ] ) + hb_eol() )
ENDIF
NEXT
RETURN aList
PROCEDURE AddProject( hProjectList, cFileName )
LOCAL cDir
LOCAL cName
LOCAL cExt
IF ! Empty( cFileName )
cFileName := hb_DirSepToOS( AllTrim( cFileName ) )
hb_FNameSplit( cFileName, @cDir, @cName, @cExt )
IF ! Empty( cName ) .AND. Empty( cDir )
cDir := cName
ENDIF
IF Empty( cName )
cName := DirGetName( cDir )
ENDIF
IF Empty( cExt )
cExt := ".hbp"
ENDIF
cFileName := hb_FNameMerge( cDir, cName, cExt )
hProjectList[ StrTran( cFileName, "\", "/" ) ] := { => }
ENDIF
RETURN
PROCEDURE LoadProjectListFromFile( hProjectList, cFileName )
LOCAL cItem
FOR EACH cItem IN hb_ATokens( StrTran( MemoRead( cFileName ), Chr( 13 ) ), Chr( 10 ) )
IF "#" $ cItem
cItem := Left( cItem, At( "#", cItem ) - 1 )
ENDIF
AddProject( hProjectList, cItem )
NEXT
RETURN
PROCEDURE LoadProjectListFromString( hProjectList, cString )
LOCAL cItem
FOR EACH cItem IN hb_ATokens( cString,, .T. )
AddProject( hProjectList, cItem )
NEXT
RETURN