diff --git a/harbour/ChangeLog b/harbour/ChangeLog index d9d0c608c2..f6d732e398 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -16,6 +16,17 @@ The license applies to all entries newer than 2009-04-28. */ +2012-11-02 16:09 UTC+0100 Viktor Szakats (harbour syenar.net) + * utils/hbmk2/hbmk2.prg + + added experimental feature, which will hint .hbc and -l + options based on list of missing symbols at link time. + It will hint components that reside in contrib and + addons components, given that they provide an .hbx + file. + + * bin/find.hb + * minor cleanups + 2012-11-02 13:41 UTC+0100 Viktor Szakats (harbour syenar.net) * bin/find.hb + only look for hbx files in 'include', 'contrib' and 'addons' diff --git a/harbour/bin/find.hb b/harbour/bin/find.hb index 572311ed3d..a900f52e59 100644 --- a/harbour/bin/find.hb +++ b/harbour/bin/find.hb @@ -30,9 +30,11 @@ PROCEDURE Main( ... ) - WalkDir( hb_DirBase() + ".." + hb_ps() + "include", { ... } ) - WalkDir( hb_DirBase() + ".." + hb_ps() + "contrib", { ... } ) - WalkDir( hb_DirBase() + ".." + hb_ps() + "addons" , { ... } ) + LOCAL cRoot := hb_DirBase() + ".." + hb_ps() + + WalkDir( cRoot + "include", { ... } ) + WalkDir( cRoot + "contrib", { ... } ) + WalkDir( cRoot + "addons" , { ... } ) RETURN @@ -61,7 +63,7 @@ STATIC PROCEDURE ProcessFile( cFileName, aContains ) LOCAL cDynamic LOCAL lFirst := .T. - FOR EACH cDynamic IN __hb_extern_get_exception_list( cFileName ) + FOR EACH cDynamic IN LoadHBX( cFileName ) IF Empty( aContains ) .OR. AScan( aContains, {| tmp | Upper( tmp ) $ Upper( cDynamic ) } ) > 0 IF lFirst lFirst := .F. @@ -73,14 +75,14 @@ STATIC PROCEDURE ProcessFile( cFileName, aContains ) RETURN -STATIC FUNCTION __hb_extern_get_exception_list( cInputName ) +STATIC FUNCTION LoadHBX( cInputName ) LOCAL cFile LOCAL pRegex LOCAL tmp LOCAL aDynamic := {} - IF ! Empty( cFile := MemoRead( cInputName ) ) .AND. ; + IF ! Empty( cFile := hb_MemoRead( cInputName ) ) .AND. ; ! Empty( pRegex := hb_regexComp( "^DYNAMIC ([a-zA-Z0-9_]*)$", .T., .T. ) ) FOR EACH tmp IN hb_regexAll( pRegex, StrTran( cFile, Chr( 13 ) ),,,,, .T. ) AAdd( aDynamic, tmp[ 2 ] ) diff --git a/harbour/utils/hbmk2/hbmk2.prg b/harbour/utils/hbmk2/hbmk2.prg index 7b17f5fd21..0c217031a5 100644 --- a/harbour/utils/hbmk2/hbmk2.prg +++ b/harbour/utils/hbmk2/hbmk2.prg @@ -1323,6 +1323,8 @@ FUNCTION hbmk( aArgs, nArgTarget, /* @ */ lPause, nLevel ) LOCAL lHBMAINDLLP + LOCAL cStdOut, cStdErr + IF s_cSecToken == NIL s_cSecToken := StrZero( hb_rand32(), 10, 0 ) ENDIF @@ -6589,7 +6591,7 @@ FUNCTION hbmk( aArgs, nArgTarget, /* @ */ lPause, nLevel ) ENDIF ENDIF - IF ! hbmk[ _HBMK_lDONTEXEC ] .AND. ( tmp := hb_processRun( cCommand ) ) != 0 + IF ! hbmk[ _HBMK_lDONTEXEC ] .AND. ( tmp := hb_processRun( cCommand,, @cStdOut, @cStdErr ) ) != 0 _hbmk_OutErr( hbmk, hb_StrFormat( I_( "Error: Running linker. %1$d" ), tmp ) ) IF ! hbmk[ _HBMK_lQuiet ] OutErr( cCommand + _OUT_EOL ) @@ -6597,6 +6599,7 @@ FUNCTION hbmk( aArgs, nArgTarget, /* @ */ lPause, nLevel ) IF ! hbmk[ _HBMK_lIGNOREERROR ] hbmk[ _HBMK_nErrorLevel ] := _ERRLEV_RUNLINKER ENDIF + AdviseMissingLibs( hbmk, cStdErr + hb_eol() + cStdOut ) ENDIF IF ! Empty( cScriptFile ) @@ -6702,7 +6705,7 @@ FUNCTION hbmk( aArgs, nArgTarget, /* @ */ lPause, nLevel ) ENDIF ENDIF - IF ! hbmk[ _HBMK_lDONTEXEC ] .AND. ( tmp := hb_processRun( cCommand ) ) != 0 + IF ! hbmk[ _HBMK_lDONTEXEC ] .AND. ( tmp := hb_processRun( cCommand,, @cStdOut, @cStdErr ) ) != 0 _hbmk_OutErr( hbmk, hb_StrFormat( I_( "Error: Running dynamic lib link command. %1$d" ), tmp ) ) IF ! hbmk[ _HBMK_lQuiet ] OutErr( cCommand + _OUT_EOL ) @@ -6710,6 +6713,7 @@ FUNCTION hbmk( aArgs, nArgTarget, /* @ */ lPause, nLevel ) IF ! hbmk[ _HBMK_lIGNOREERROR ] hbmk[ _HBMK_nErrorLevel ] := _ERRLEV_RUNLINKER ENDIF + AdviseMissingLibs( hbmk, cStdErr + hb_eol() + cStdOut ) ENDIF IF ! Empty( cScriptFile ) @@ -12202,6 +12206,144 @@ STATIC FUNCTION MacOSXFiles( hbmk, nType, cPROGNAME ) RETURN cString +STATIC PROCEDURE AdviseMissingLibs( hbmk, cOutput ) + + LOCAL hAll := GetListOfFunctionsKnown() + LOCAL aFunction := ExtractHarbourSymbols( cOutput ) + LOCAL cFunction + LOCAL aLib + LOCAL cLib + LOCAL tmp + + LOCAL hNeeded := { => } + + FOR EACH cFunction IN aFunction DESCEND + IF cFunction $ hAll + FOR EACH cLib IN hb_ATokens( hAll[ cFunction ], "," ) + IF !( cLib $ hNeeded ) + hNeeded[ cLib ] := {} + ENDIF + AAddNew( hNeeded[ cLib ], cFunction ) + NEXT + hb_ADel( aFunction, cFunction:__enumIndex(), .T. ) + ENDIF + NEXT + + FOR EACH tmp IN hNeeded + aLib := LibReferenceToOption( tmp:__enumKey() ) + _hbmk_OutStd( hbmk, hb_StrFormat( "Hint: Add option '%1$s'%2$s for missing function(s): %3$s", ; + aLib[ 1 ], ; + iif( aLib[ 2 ], "", " (not installed)" ), ; + ArrayToList( tmp, ", ",,,, "()" ) ) ) + NEXT + + IF ! Empty( aFunction ) + _hbmk_OutStd( hbmk, hb_StrFormat( "Error: Referenced, missing, but unknown function(s): %1$s", ArrayToList( aFunction, ", ",,,, "()" ) ) ) + ENDIF + + RETURN + +STATIC FUNCTION LibReferenceToOption( cLib ) + + LOCAL lInstalled + LOCAL cRoot := hb_DirBase() + ".." + hb_ps() + + IF Left( cLib, 1 ) == "(" + cLib := "-l" + SubStr( cLib, 2, Len( cLib ) - 2 ) + lInstalled := .T. + ELSE + lInstalled := hb_FileExists( cRoot + hb_ps() + hb_FNameExtSet( PathSepToSelf( cLib ), ".hbc" ) ) + /* detect autofind libs */ + IF ( Left( cLib, Len( "contrib" + "/" ) ) == "contrib" + "/" .AND. ; + "contrib" + "/" + hb_FNameName( cLib ) + "/" + hb_FNameName( cLib ) + ".hbx" == cLib ) .OR. ; + ( Left( cLib, Len( "addons" + "/" ) ) == "addons" + "/" .AND. ; + "addons" + "/" + hb_FNameName( cLib ) + "/" + hb_FNameName( cLib ) + ".hbx" == cLib ) + cLib := hb_FNameName( cLib ) + ".hbc" + ELSE + cLib := hb_FNameExtSet( PathSepToSelf( cLib ), ".hbc" ) + ENDIF + ENDIF + + RETURN { cLib, lInstalled } + +STATIC FUNCTION ExtractHarbourSymbols( cString ) + + LOCAL aList + LOCAL pRegex + LOCAL tmp + LOCAL cOldCP + + cOldCP := hb_cdpSelect( "EN" ) + IF ! Empty( pRegex := hb_regexComp( "HB_FUN_([A-Z][A-Z0-9_]*)", .T., .T. ) ) + aList := hb_regexAll( pRegex, StrTran( cString, Chr( 13 ) ),,,,, .T. ) + FOR EACH tmp IN aList + tmp := tmp[ 2 ] + NEXT + ELSE + aList := {} + ENDIF + hb_cdpSelect( cOldCP ) + + RETURN aList + +STATIC FUNCTION GetListOfFunctionsKnown() + LOCAL cRoot := hb_DirBase() + ".." + hb_ps() + LOCAL cFileName := hb_DirBase() + "hbmk2.hbr" + + LOCAL hAll := iif( hb_FileExists( cFileName ), hb_Deserialize( hb_ZUncompress( hb_MemoRead( cFileName ) ) ), { => } ) + + IF ! HB_ISHASH( hAll ) + hAll := { => } + ENDIF + + hAll[ "HB_COMPILE" ] := ; + hAll[ "HB_COMPILEBUF" ] := ; + hAll[ "HB_COMPILEFROMBUFF" ] := "(hbcplr)" + + GetListOfFunctionsKnownWalkDir( cRoot + "contrib", cRoot, hAll ) + GetListOfFunctionsKnownWalkDir( cRoot + "addons", cRoot, hAll ) + + RETURN hAll + +STATIC PROCEDURE GetListOfFunctionsKnownWalkDir( cDir, cRoot, hAll ) + + LOCAL aFile + + cDir := hb_DirSepAdd( PathSepToSelf( cDir ) ) + + FOR EACH aFile IN Directory( cDir + hb_osFileMask(), "D" ) + IF aFile[ F_NAME ] == "." .OR. aFile[ F_NAME ] == ".." + ELSEIF "D" $ aFile[ F_ATTR ] + GetListOfFunctionsKnownWalkDir( cDir + aFile[ F_NAME ] + hb_ps(), cRoot, hAll ) + ELSEIF hb_FNameExt( aFile[ F_NAME ] ) == ".hbx" + GetListOfFunctionsKnownProcessHBX( cDir + aFile[ F_NAME ], cRoot, hAll ) + ENDIF + NEXT + + RETURN + +STATIC FUNCTION GetListOfFunctionsKnownProcessHBX( cFileName, cRoot, hAll ) + + LOCAL cName := StrTran( SubStr( cFileName, Len( cRoot ) + 1 ), "\", "/" ) + + LOCAL cFile + LOCAL pRegex + LOCAL tmp + LOCAL aDynamic := {} + + IF ! Empty( cFile := hb_MemoRead( cFileName ) ) .AND. ; + ! Empty( pRegex := hb_regexComp( "^DYNAMIC ([a-zA-Z0-9_]*)$", .T., .T. ) ) + FOR EACH tmp IN hb_regexAll( pRegex, StrTran( cFile, Chr( 13 ) ),,,,, .T. ) + IF tmp[ 2 ] $ hAll + hAll[ tmp[ 2 ] ] += "," + cName + ELSE + hAll[ tmp[ 2 ] ] := cName + ENDIF + NEXT + ENDIF + + RETURN aDynamic + STATIC FUNCTION mk_extern( hbmk, cInputName, cBin_LibHBX, cOpt_LibHBX, cLibHBX_Regex, cOutputName ) LOCAL aExtern