* utils/hbmk2/hbmk2.prg
+ will now add lib/3rd dir to the link commands, so
unicows lib will be found in uninstalled Harbour SVN
source tree.
* contrib/make.hbs
* contrib/hbpost.hbm
+ automatically enable unicows support for contribs, if available.
- deleted support for undocumented __HB_BUILD_WINUNI envvar
* config/global.mk
* config/rules.mk
- deleted support for undocumented __HB_BUILD_WINUNI envvar
* package/winuni/mpkg_win_uni.bat
* package/mpkg_win_nightly.bat
- deleted special support for unicows libs for nightly
and official releases, along with HB_DIR_UNICOWS envvar.
Now these libs are included in all builds.
* config/win/global.mk
+ automatically enable unicows support for core, if available.
* config/win/xcc.mk
* config/win/icc.mk
* config/win/mingw.mk
* config/win/pocc.mk
* config/win/bcc.mk
* config/win/msvc.mk
+ added support for SYSLIBPATHS. (used by unicows support)
! fixed bcc dynlib link command missing libpaths.
; NOTE: watcom unicows support is missing, as it needs
special tricks due to missing separate libpath option
in this compiler/linker.
* config/wce/mingwarm.mk
* config/wce/poccarm.mk
* config/wce/msvcarm.mk
* synced with config/win files
+ config/libbin.mk
+ added rule to install pre-built binary libs.
(for unicows libs)
* Makefile
+ lib/3rd
+ lib/3rd/win
+ lib/3rd/win/mingw
+ lib/3rd/win/mingw/Makefile
+ lib/3rd/win/mingw/libunicows.a
+ lib/3rd/win/mingw/libunicows_license.txt
+ lib/3rd/win/bcc
+ lib/3rd/win/bcc/unicows_license.txt
+ lib/3rd/win/bcc/unicows.lib
+ lib/3rd/win/bcc/Makefile
+ added locally hosted unicows runtime/implibs from:
http://libunicows.sourceforge.net/ by author Vaclav Slavik.
With these libs, it's possible to use UNICODE builds
with both MS unicows.dll and opencows .dll on legacy
Windows-system (Win9x).
These libs will be installed to Harbour core lib directory,
and also used from lib/3rd directory, if they are available.
I've uploaed mingw and bcc libs because these are used
nearly exclusively by users, but they are also available
for older msvc, watcom, dmc and lcc compilers. I don't
think it's worth the extra size to support Win9x using
these legacy compilers, anyhow they can be added easily
if needed (except watcom, which requires more work).
; These changes mean three things:
1. Harbour now has only one build mode on Windows: UNICODE
This will greatly simplify coding and testing and will
allow to focus much better on what's important. It also
allows to drop lots of dual code dealing with separate
UNICODE and non-UNICODE branches.
2. Harbour default builds will now run on Win9x (currently
when using mingw or bcc compilers), though UNICOWS.DLL
is now required. See INSTALL how to get this free .dll
from MS. This also means that Harbour can now theoretically
by built on Win9x systems (I didn't try).
3. Harbour users can create UNICODE builds compatible with
Win9x, by simply adding -lunicows to their .hbp projects.
No extra installation is required.
782 lines
24 KiB
Handlebars
Executable File
782 lines
24 KiB
Handlebars
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/).
|
|
*
|
|
*/
|
|
|
|
/* TODO (long term, low priority):
|
|
1. normalize path to hbpre/hbpost to save on cmdline
|
|
(after normalizer function has been moved to core)
|
|
2. Move lib output dir and workdirs inside contrib dirs.
|
|
3. Make home project detection more robust in stdalone mode.
|
|
|
|
NOTE:
|
|
- 'install' is ignored in stdalone mode. It would be needed to
|
|
replicate the install dir defaulting logic found in global.mk
|
|
to implement it.
|
|
*/
|
|
|
|
#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 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
|
|
|
|
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__HBRUN )
|
|
s_cBinDir := hbrun_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
|
|
|
|
/* Strip install action */
|
|
DO CASE
|
|
CASE nAction == _ACT_INC_REBUILD_INST ; nAction := _ACT_INC_REBUILD
|
|
CASE nAction == _ACT_INC_INST ; 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( PathSepToSelf( 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$s project(s)", hActions[ nAction ], hb_ntos( 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 )
|
|
|
|
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( PathSepToSelf( cProject ), PathSepToSelf( tmp:__enumKey() ) ) .OR. ;
|
|
hb_FileMatch( PathSepToSelf( cProject ), hb_DirSepDel( hb_FNameDir( PathSepToSelf( 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" ) )
|
|
hb_setenv( "_HB_UNICOWS_AVAILABLE", iif( hb_DirExists( s_cRoot + "lib" + hb_ps() + "3rd" + hb_ps() + GetEnv( "HB_PLATFORM" ) + hb_ps() + GetEnv( "HB_COMPILER" ) ), "yes", "" ) )
|
|
|
|
/* 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...", hActions[ nAction ] ) + hb_eol() )
|
|
|
|
build_projects( nAction, hProjectList, hProjectReqList, "" )
|
|
|
|
OutStd( hb_StrFormat( "! Finished package %1$s...", hActions[ nAction ] ) + hb_eol() )
|
|
|
|
RETURN
|
|
|
|
STATIC PROCEDURE build_projects( nAction, hProjectList, hProjectReqList, cOptionsUser )
|
|
LOCAL aPairList
|
|
LOCAL aSortedList
|
|
|
|
LOCAL cOptions
|
|
LOCAL lInstall
|
|
|
|
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$s projects...", hb_ntos( 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 on 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
|
|
|
|
lInstall := nAction == _ACT_INC_INST .OR. ;
|
|
nAction == _ACT_INC_REBUILD_INST
|
|
|
|
hb_setenv( "_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( PathSepToSelf( 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 nErrorLevel
|
|
|
|
hProject[ "cType" ] := ""
|
|
hProject[ "aDept" ] := {}
|
|
hProject[ "lChecked" ] := NIL
|
|
|
|
IF ( nErrorLevel := call_hbmk2( cProjectPath, " --hbinfo", NIL,, @cStdOut ) ) == 0
|
|
|
|
hProject[ "cType" ] := hbmk2_hbinfo_getitem( cStdOut, "targettype" )
|
|
hProject[ "cOutputName" ] := hbmk2_hbinfo_getitem( cStdOut, "outputname" )
|
|
hProject[ "cDynSuffix" ] := hbmk2_hbinfo_getitem( cStdOut, "dynsuffix" )
|
|
hProject[ "cPlatform" ] := hbmk2_hbinfo_getitem( cStdOut, "platform" )
|
|
|
|
FOR EACH tmp IN hb_ATokens( hbmk2_hbinfo_getitem( cStdOut, "hbctree", .T. ), 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( PathSepToSelf( LTrim( tmp ) ), ".hbp" ) ) ), "\", "/" ) } )
|
|
ENDIF
|
|
NEXT
|
|
ENDIF
|
|
|
|
RETURN nErrorLevel
|
|
|
|
STATIC FUNCTION hbmk2_hbinfo_getitem( cString, cItem, lAll )
|
|
LOCAL cRetVal := ""
|
|
LOCAL nPos := 1
|
|
LOCAL tmp
|
|
|
|
DO WHILE ( tmp := hb_At( cItem + "{{", cString, nPos ) ) > 0
|
|
nPos := tmp + Len( cItem + "{{" )
|
|
IF ( tmp := hb_At( "}}", cString, nPos ) ) > 0
|
|
tmp := StrTran( SubStr( cString, nPos, tmp - nPos ), Chr( 13 ) )
|
|
IF lAll != NIL .AND. lAll
|
|
cRetVal += tmp
|
|
ELSE
|
|
/* Find the last occurrence, which is the root project */
|
|
cRetVal := tmp
|
|
ENDIF
|
|
ENDIF
|
|
ENDDO
|
|
|
|
RETURN cRetVal
|
|
|
|
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) */
|
|
hb_setenv( "_HB_BUILD_LIBDYN", "yes" )
|
|
|
|
IF hb_FileExists( hb_FNameExtSet( cProjectPath, ".hbc" ) )
|
|
cOptionsLibDyn += " " + hb_FNameExtSet( cProjectPath, ".hbc" )
|
|
ENDIF
|
|
ELSE
|
|
hb_setenv( "_HB_DYNSUFF" )
|
|
hb_setenv( "_HB_BUILD_LIBDYN" )
|
|
ENDIF
|
|
|
|
hb_setenv( "_HB_CONTRIB_SUBDIR", hb_FNameDir( PathSepToSelf( cProjectPath ) ) )
|
|
|
|
cCommand := s_cBinDir + "hbmk2" +;
|
|
" -quiet -width=0" +;
|
|
" @" + 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
|
|
|
|
IF nErrorLevel != 0
|
|
OutStd( hb_StrFormat( "! '%1$s' returned status: %2$s", cProjectPath, hb_ntos( nErrorLevel ) ) + hb_eol() )
|
|
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 := PathSepToSelf( 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
|
|
|
|
STATIC FUNCTION PathSepToSelf( cFileName )
|
|
RETURN StrTran( cFileName, iif( hb_ps() == "\", "/", "\" ), hb_ps() )
|
|
|
|
/* 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 := PathSepToSelf( 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
|