#!/usr/bin/env hbmk2 /* * This Harbour script is part of the GNU Make-based build system. * WARNING: Running it separately is not supported. * * Copyright 2009-2010 Viktor Szakats (vszakats.net/harbour) * Copyright 2003 Przemyslaw Czerpak (druzus/at/priv.onet.pl) (embedded autoinstall bash script) * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * (or visit their website at https://www.gnu.org/licenses/). * */ #pragma -w3 #pragma -km+ #pragma -ko+ #include "directry.ch" #include "fileio.ch" PROCEDURE Main( ... ) LOCAL nErrorLevel := 0 LOCAL aFile LOCAL tmp, tmp1 LOCAL cOldDir LOCAL cTar_Name LOCAL cTar_NameExt LOCAL cTar_Path LOCAL cBin_Tar LOCAL lGNU_Tar LOCAL cOwner LOCAL cGroup LOCAL cSH_Script LOCAL nAttr LOCAL cDynVersionFull LOCAL cDynVersionComp LOCAL cDynVersionless IF Empty( GetEnvC( "HB_PLATFORM" ) ) .OR. ; Empty( GetEnvC( "HB_COMPILER" ) ) .OR. ; Empty( GetEnvC( "HB_HOST_BIN_DIR" ) ) OutStd( "! Error: This script has to be called from the GNU Make process." + hb_eol() ) ErrorLevel( 1 ) RETURN ENDIF /* Detect install build phase */ IF AScan( hb_AParams(), {| tmp | Lower( tmp ) == "install" } ) > 0 /* Installing some misc files */ tmp := GetEnvC( "HB_INSTALL_DOC" ) IF ! tmp == "no" IF GetEnvC( "HB_PLATFORM" ) $ "win|wce|os2|dos" tmp := GetEnvC( "HB_INSTALL_PREFIX" ) ENDIF IF ! Empty( tmp ) OutStd( "! Copying root documents..." + hb_eol() ) IF hb_DirBuild( hb_DirSepToOS( tmp ) ) FOR EACH aFile IN Directory( "Change*" ) mk_hb_FCopy( aFile[ F_NAME ], tmp + hb_ps() + iif( GetEnvC( "HB_PLATFORM" ) == "dos", "CHANGES", "" ) ) NEXT mk_hb_FCopy( "LICENSE.txt", tmp + hb_ps() ) mk_hb_FCopy( "README.md", tmp + hb_ps() ) ELSE OutStd( hb_StrFormat( "! Error: Cannot create directory '%1$s'", tmp ) + hb_eol() ) ENDIF ENDIF ENDIF IF ! Empty( GetEnvC( "HB_INSTALL_BIN" ) ) .AND. ; ! GetEnvC( "HB_BUILD_PARTS" ) == "lib" OutStd( "! Copying Harbour script files..." + hb_eol() ) /* public Harbour scripts */ FOR EACH tmp IN { ; "bin/3rdpatch.hb", ; "bin/check.hb", ; "bin/commit.hb", ; "bin/harbour.ucf" } mk_hb_FCopy( tmp, GetEnvC( "HB_INSTALL_BIN" ) + hb_ps() ) NEXT ENDIF IF ! Empty( GetEnvC( "HB_INSTALL_ETC" ) ) OutStd( "! Copying *nix config files..." + hb_eol() ) IF hb_DirBuild( hb_DirSepToOS( GetEnvC( "HB_INSTALL_ETC" ) ) ) mk_hb_FCopy( "src/rtl/gtcrs/hb-charmap.def", GetEnvC( "HB_INSTALL_ETC" ) + hb_ps(), .T. ) ELSE OutStd( hb_StrFormat( "! Error: Cannot create directory '%1$s'", GetEnvC( "HB_INSTALL_ETC" ) ) + hb_eol() ) ENDIF IF GetEnvC( "HB_PLATFORM" ) $ "linux" .AND. ; ! Empty( GetEnvC( "HB_INSTALL_DYN" ) ) OutStd( "! Creating Linux ld config file..." + hb_eol() ) tmp := GetEnvC( "HB_INSTALL_ETC" ) + hb_ps() + ".." + hb_ps() + "ld.so.conf.d" IF hb_DirBuild( hb_DirSepToOS( tmp ) ) tmp1 := GetEnvC( "HB_INSTALL_DYN" ) IF Left( tmp1, Len( GetEnvC( "HB_INSTALL_PKG_ROOT" ) ) ) == GetEnvC( "HB_INSTALL_PKG_ROOT" ) tmp1 := SubStr( tmp1, Len( GetEnvC( "HB_INSTALL_PKG_ROOT" ) ) + 1 ) ENDIF hb_MemoWrit( tmp + hb_ps() + "harbour.conf", tmp1 + hb_eol() ) ELSE OutStd( hb_StrFormat( "! Error: Cannot create directory '%1$s'", tmp ) + hb_eol() ) ENDIF ENDIF ENDIF IF ! Empty( GetEnvC( "HB_INSTALL_MAN" ) ) OutStd( "! Copying *nix man files..." + hb_eol() ) IF hb_DirBuild( hb_DirSepToOS( GetEnvC( "HB_INSTALL_MAN" ) ) + hb_ps() + "man1" ) FOR EACH tmp IN { ; "src/main/harbour.1", ; "src/pp/hbpp.1" } mk_hb_FCopy( tmp, GetEnvC( "HB_INSTALL_MAN" ) + hb_ps() + "man1" + hb_ps(), .T. ) NEXT ELSE OutStd( hb_StrFormat( "! Error: Cannot create directory '%1$s'", GetEnvC( "HB_INSTALL_MAN" ) ) + hb_eol() ) ENDIF ENDIF IF ! GetEnvC( "HB_PLATFORM" ) $ "win|wce|os2|dos|cygwin" .AND. ; ! Empty( GetEnvC( "HB_INSTALL_DYN" ) ) .AND. ; hb_FileExists( hb_DirSepToOS( GetEnvC( "HB_DYNLIB_DIR" ) ) + hb_ps() + GetEnvC( "HB_DYNLIB_PREF" ) + GetEnvC( "HB_DYNLIB_BASE" ) + GetEnvC( "HB_DYNLIB_POST" ) + GetEnvC( "HB_DYNLIB_EXT" ) + GetEnvC( "HB_DYNLIB_PEXT" ) ) OutStd( "! Creating dynamic lib symlinks..." + hb_eol() ) cDynVersionFull := GetEnvC( "HB_DYNLIB_PREF" ) + GetEnvC( "HB_DYNLIB_BASE" ) + GetEnvC( "HB_DYNLIB_POST" ) + GetEnvC( "HB_DYNLIB_EXT" ) + GetEnvC( "HB_DYNLIB_PEXT" ) cDynVersionComp := GetEnvC( "HB_DYNLIB_PREF" ) + GetEnvC( "HB_DYNLIB_BASE" ) + GetEnvC( "HB_DYNLIB_POSC" ) + GetEnvC( "HB_DYNLIB_EXT" ) + GetEnvC( "HB_DYNLIB_PEXC" ) cDynVersionless := GetEnvC( "HB_DYNLIB_PREF" ) + GetEnvC( "HB_DYNLIB_BASE" ) + GetEnvC( "HB_DYNLIB_EXT" ) IF ! cDynVersionFull == cDynVersionComp mk_hb_FLinkSym( cDynVersionFull, hb_DirSepToOS( GetEnvC( "HB_INSTALL_DYN" ) ) + hb_ps() + cDynVersionComp ) ENDIF IF ! cDynVersionFull == cDynVersionless mk_hb_FLinkSym( cDynVersionFull, hb_DirSepToOS( GetEnvC( "HB_INSTALL_DYN" ) ) + hb_ps() + cDynVersionless ) ENDIF DO CASE CASE EndsWith( GetEnvC( "HB_INSTALL_DYN" ), "/usr/lib/harbour" ) .OR. ; EndsWith( GetEnvC( "HB_INSTALL_DYN" ), "/usr/lib64/harbour" ) .OR. ; EndsWith( GetEnvC( "HB_INSTALL_DYN" ), "/usr/local/lib/harbour" ) .OR. ; EndsWith( GetEnvC( "HB_INSTALL_DYN" ), "/usr/local/lib64/harbour" ) IF ! cDynVersionFull == cDynVersionless mk_hb_FLinkSym( "harbour" + hb_ps() + cDynVersionFull, hb_DirSepToOS( GetEnvC( "HB_INSTALL_DYN" ) ) + hb_ps() + ".." + hb_ps() + cDynVersionless ) ENDIF IF ! cDynVersionFull == cDynVersionComp mk_hb_FLinkSym( "harbour" + hb_ps() + cDynVersionFull, hb_DirSepToOS( GetEnvC( "HB_INSTALL_DYN" ) ) + hb_ps() + ".." + hb_ps() + cDynVersionComp ) ENDIF mk_hb_FLinkSym( "harbour" + hb_ps() + cDynVersionFull, hb_DirSepToOS( GetEnvC( "HB_INSTALL_DYN" ) ) + hb_ps() + ".." + hb_ps() + cDynVersionFull ) CASE GetEnvC( "HB_INSTALL_DYN" ) == "/usr/local/harbour/lib" /* FIXME: Rewrite this in .prg: ld="/usr/lib" if [ -n "${HB_INST_PKGPREF}" ] || [ -w $ld ] then mkdir -p ${HB_INST_PKGPREF}$ld ln -sf ../local/harbour/lib/$l ${HB_INST_PKGPREF}$ld/$ll ln -sf ../local/harbour/lib/$l ${HB_INST_PKGPREF}$ld/$l fi */ ENDCASE ENDIF /* Creating language files */ IF ! Empty( GetEnvC( "HB_INSTALL_BIN" ) ) .AND. ; ! GetEnvC( "HB_BUILD_PARTS" ) == "lib" OutStd( "! Making core translation (.hbl) files..." + hb_eol() ) FOR EACH tmp IN Directory( "utils" + hb_ps() + hb_osFileMask(), "D" ) IF "D" $ tmp[ F_ATTR ] .AND. !( tmp[ F_NAME ] == "." ) .AND. !( tmp[ F_NAME ] == ".." ) FOR EACH aFile IN Directory( hb_DirSepToOS( "utils/" + tmp[ F_NAME ] + "/po/*.po" ) ) mk_hbl( hb_DirSepToOS( "utils/" + tmp[ F_NAME ] + "/po/" + aFile[ F_NAME ] ), ; hb_DirSepToOS( GetEnvC( "HB_INSTALL_BIN" ) ) + hb_ps() + hb_FNameExtSet( aFile[ F_NAME ], ".hbl" ) ) NEXT ENDIF NEXT ENDIF /* Creating docs for core */ IF ! Empty( tmp := GetEnvC( "HB_INSTALL_DOC" ) ) .AND. ! tmp == "no" OutStd( "! Compiling core documentation (.hbd)..." + hb_eol() ) mk_hbd_core( "." + hb_ps(), tmp ) ENDIF /* Creating compressed archives of available contrib functions */ IF ! Empty( tmp := GetEnvC( "HB_INSTALL_BIN" ) ) OutStd( "! Compiling list of contrib functions (.hbr)..." + hb_eol() ) mk_hbr( tmp ) ENDIF /* Creating release packages */ IF GetEnvC( "HB_BUILD_PKG" ) == "yes" .AND. ; ! Empty( GetEnvC( "HB_TOP" ) ) IF GetEnvC( "HB_PLATFORM" ) $ "win|wce|os2|dos" tmp := GetEnvC( "HB_TOP" ) + hb_ps() + GetEnvC( "HB_PKGNAME" ) + ".zip" OutStd( "! Making Harbour .zip install package: '" + tmp + "'" + hb_eol() ) FErase( tmp ) /* NOTE: Believe it or not this is the official method to zip a different dir with subdirs without including the whole root path in filenames; you have to 'cd' into it. Even with zip 3.0. For this reason we need absolute path in HB_TOP. There is also no zip 2.x compatible way to force creation of a new .zip, so we have to delete it first to avoid mixing in an existing .zip file. [vszakats] */ cOldDir := hb_cwd( GetEnvC( "HB_INSTALL_PKG_ROOT" ) ) mk_hb_processRun( hb_DirSepToOS( GetEnvC( "HB_DIR_ZIP" ) ) + "zip" + ; " -q -9 -X -r -o" + ; " " + FNameEscape( tmp ) + ; " . -i " + FNameEscape( GetEnvC( "HB_PKGNAME" ) + hb_ps() + "*" ) + ; " -x *.tds -x *.exp" ) hb_cwd( cOldDir ) IF GetEnvC( "HB_PLATFORM" ) $ "win|wce" tmp := GetEnvC( "HB_TOP" ) + hb_ps() + GetEnvC( "HB_PKGNAME" ) + ".exe" OutStd( "! Making Harbour .exe install package: '" + tmp + "'" + hb_eol() ) mk_hb_processRun( hb_DirSepToOS( GetEnvC( "HB_DIR_NSIS" ) ) + "makensis.exe" + ; " -V2" + ; " " + FNameEscape( StrTran( "package/mpkg_win.nsi", "/", hb_ps() ) ) ) ENDIF ELSE cBin_Tar := "tar" lGNU_Tar := .T. IF ! Empty( query_stdout( "gtar --version" ) ) cBin_Tar := "gtar" ELSEIF Empty( query_stdout( "tar --version" ) ) cBin_Tar := "" ELSEIF "bsdtar" $ query_stdout( "tar --version" ) /* tar is mapped to bsdtar starting OS X 10.6 */ lGNU_Tar := .F. ENDIF IF ! Empty( cBin_Tar ) cTar_Name := GetEnvC( "HB_PKGNAME" ) IF ! Empty( tmp := unix_name() ) cTar_Name += "-" + tmp ENDIF cTar_NameExt := cTar_Name + iif( GetEnvC( "HB_PLATFORM" ) == "dos", ".tgz", ".bin.tar.gz" ) cTar_Path := GetEnvC( "HB_TOP" ) + hb_ps() + cTar_NameExt OutStd( "! Making Harbour tar install package: '" + cTar_Path + "'" + hb_eol() ) FErase( cTar_Path ) cOwner := "root" cGroup := iif( ; GetEnvC( "HB_PLATFORM" ) == "darwin" .OR. ; GetEnvC( "HB_PLATFORM" ) == "bsd", "wheel", "root" ) cOldDir := hb_cwd( GetEnvC( "HB_INSTALL_PKG_ROOT" ) ) /* TODO: Add support for non-GNU non-BSD tar (which gets the data from stdio) */ mk_hb_processRun( cBin_Tar + ; " czvf" + ; " " + FNameEscape( cTar_Path ) + ; iif( lGNU_Tar, " --owner=" + cOwner + " --group=" + cGroup, "" ) + ; " ." ) hb_cwd( cOldDir ) IF ! GetEnvC( "HB_PLATFORM" ) == "dos" tmp := GetEnvC( "HB_TOP" ) + hb_ps() + cTar_Name + ".inst.sh" OutStd( "! Making Harbour tar installer package: '" + tmp + "'" + hb_eol() ) /* In the generated script always use tar because we can't be sure if cBin_Tar exists in the installation environment */ cSH_Script := ; '#!/bin/sh' + Chr( 10 ) + ; 'if [ "\$1" = "--extract" ]; then' + Chr( 10 ) + ; ' tail -c ' + hb_ntos( hb_FSize( cTar_Path ) ) + ' "\$0" > "' + cTar_NameExt + '"' + Chr( 10 ) + ; ' exit' + Chr( 10 ) + ; 'fi' + Chr( 10 ) + ; 'if [ \`id -u\` != 0 ]; then' + Chr( 10 ) + ; ' echo "This package has to be installed from root account."' + Chr( 10 ) + ; ' exit 1' + Chr( 10 ) + ; 'fi' + Chr( 10 ) + ; 'echo "Do you want to install Harbour (y/n)"' + Chr( 10 ) + ; 'read ASK' + Chr( 10 ) + ; 'if [ "\${ASK}" != "y" ] && [ "\${ASK}" != "Y" ]; then' + Chr( 10 ) + ; ' exit 1' + Chr( 10 ) + ; 'fi' + Chr( 10 ) + ; '(tail -c ' + hb_ntos( hb_FSize( cTar_Path ) ) + ' "\$0" | gzip -cd | (cd /;tar xvpf -)) ' + iif( GetEnvC( "HB_PLATFORM" ) == "linux", "&& ldconfig", "" ) + Chr( 10 ) + ; 'exit \$?' + Chr( 10 ) + ; 'HB_INST_EOF' + Chr( 10 ) hb_MemoWrit( tmp, cSH_Script + hb_MemoRead( cTar_Path ) ) hb_FGetAttr( tmp, @nAttr ) hb_FSetAttr( tmp, hb_bitOr( nAttr, HB_FA_XOTH ) ) ENDIF ELSE OutStd( "! Error: Cannot find 'tar' tool" + hb_eol() ) ENDIF ENDIF ENDIF /* Executing user postinst configuration script */ IF ! Empty( tmp := GetEnvC( "HB_INSTALL_SCRIPT" ) ) mk_hb_processRun( tmp ) ENDIF ELSE /* Regenerating extern headers */ mk_extern_core() ENDIF OutStd( "! postinst script finished" + ; iif( nErrorLevel == 0, "", " with with errorlevel=" + hb_ntos( nErrorLevel ) ) + hb_eol() ) ErrorLevel( nErrorLevel ) RETURN STATIC FUNCTION mk_hbl( cIn, cOut ) LOCAL cErrorMsg LOCAL aTrans aTrans := __i18n_potArrayLoad( cIn, @cErrorMsg ) IF aTrans != NIL IF hb_MemoWrit( cOut, hb_i18n_SaveTable( __i18n_hashTable( __i18n_potArrayToHash( aTrans, .F. ) ) ) ) OutStd( "! Created " + cOut + " <= " + cIn + hb_eol() ) RETURN .T. ELSE OutErr( "! Error: Cannot create file: " + cOut + hb_eol() ) ENDIF ELSE OutErr( "! Error: Loading translation: " + cIn + " (" + cErrorMsg + ")" + hb_eol() ) ENDIF RETURN .F. STATIC FUNCTION mk_hbd_core( cDirSource, cDirDest ) LOCAL cName := "harbour" LOCAL tmp LOCAL aErrMsg := {} LOCAL aEntry := __hbdoc_LoadDir( cDirSource, cName, aErrMsg ) FOR EACH tmp IN aErrMsg OutErr( hb_StrFormat( "! %1$s", tmp ) + hb_eol() ) NEXT IF ! Empty( aEntry ) cName := hb_DirSepAdd( hb_DirSepToOS( cDirDest ) ) + cName + ".hbd" IF __hbdoc_SaveHBD( cName, aEntry ) OutStd( "! Created " + cName + " <= " + cDirSource + hb_eol() ) RETURN .T. ELSE OutErr( hb_StrFormat( "! Error: Saving '%1$s'", cName ) + hb_eol() ) ENDIF ENDIF RETURN .F. STATIC FUNCTION mk_hb_processRun( cCommand, ... ) OutStd( cCommand + hb_eol() ) RETURN hb_processRun( cCommand, ... ) STATIC FUNCTION FNameEscape( cFileName ) RETURN '"' + cFileName + '"' /* Like hb_FCopy(), but accepts dir as target and can set attributes */ STATIC PROCEDURE mk_hb_FCopy( cSrc, cDst, l644 ) LOCAL cDir, cName, cExt hb_default( @l644, .F. ) cSrc := hb_DirSepToOS( cSrc ) cDst := hb_DirSepToOS( cDst ) hb_FNameSplit( cDst, @cDir, @cName, @cExt ) IF Empty( cName ) .AND. Empty( cExt ) hb_FNameSplit( cSrc,, @cName, @cExt ) ENDIF cDst := hb_FNameMerge( cDir, cName, cExt ) IF hb_FCopy( cSrc, cDst ) == 0 #if 0 OutStd( hb_StrFormat( "! Copied: %1$s <= %2$s", cDst, cSrc ) + hb_eol() ) #endif IF l644 hb_FSetAttr( cDst, hb_bitOr( HB_FA_RUSR, HB_FA_WUSR, HB_FA_RGRP, HB_FA_ROTH ) ) ENDIF #if 0 ELSE OutStd( hb_StrFormat( "! Error: Copying %1$s <= %2$s", cDst, cSrc ) + hb_eol() ) #endif ENDIF RETURN /* Like hb_FLinkSym(), but with feedback */ STATIC PROCEDURE mk_hb_FLinkSym( cDst, cSrc ) FErase( cSrc ) /* remove old links if any */ IF hb_FLinkSym( cDst, cSrc ) == 0 OutStd( hb_StrFormat( "! Symlink: %1$s <= %2$s", cDst, cSrc ) + hb_eol() ) ELSE OutStd( hb_StrFormat( "! Error: Creating symlink %1$s <= %2$s (%3$d)", cDst, cSrc, FError() ) + hb_eol() ) IF FError() == 5 .AND. Empty( hb_FNameDir( cDst ) ) cDst := hb_FnameMerge( hb_FNameDir( cSrc ), cDst ) IF hb_FLink( cDst, cSrc ) == 0 OutStd( hb_StrFormat( "! Hardlink: %1$s <= %2$s", cDst, cSrc ) + hb_eol() ) ELSE OutStd( hb_StrFormat( "! Error: Creating hardlink %1$s <= %2$s (%3$d)", cDst, cSrc, FError() ) + hb_eol() ) IF hb_FCopy( cDst, cSrc ) == 0 OutStd( hb_StrFormat( "! Copyfile: %1$s <= %2$s", cDst, cSrc ) + hb_eol() ) ELSE OutStd( hb_StrFormat( "! Error: Copying file %1$s <= %2$s (%3$d)", cDst, cSrc, FError() ) + hb_eol() ) ENDIF ENDIF ENDIF ENDIF RETURN STATIC FUNCTION EndsWith( cString, cEnd ) RETURN Right( cString, Len( cEnd ) ) == cEnd STATIC FUNCTION query_stdout( cName ) LOCAL cStdOut LOCAL cStdErr LOCAL nRetVal nRetVal := hb_processRun( cName,, @cStdOut, @cStdErr ) RETURN iif( nRetVal == 0, AllTrim( StrTran( cStdOut, Chr( 10 ), " " ) ), "" ) STATIC FUNCTION query_rpm( cName, cID ) LOCAL cResult := query_stdout( "rpm -q --queryformat='.%{VERSION}' " + cName ) RETURN iif( Empty( cResult ), "", cID + AllTrim( StrTran( StrTran( cResult, Chr( 10 ), " " ), "." ) ) ) /* Please add your distro suffix if it not belong to the one recognized below and remember that order checking can be important */ STATIC FUNCTION unix_name() LOCAL tmp DO CASE CASE GetEnvC( "HB_PLATFORM" ) == "dos" ; RETURN "djgpp" CASE GetEnvC( "HB_PLATFORM" ) == "win" ; RETURN GetEnvC( "HB_COMPILER" ) CASE ! Empty( tmp := query_rpm( "mandriva-release-One", "mdv" ) ) ; RETURN tmp CASE ! Empty( tmp := query_rpm( "mandriva-release" , "mdv" ) ) ; RETURN tmp CASE ! Empty( tmp := query_rpm( "redhat-release" , "rh" ) ) ; RETURN tmp CASE ! Empty( tmp := query_rpm( "fedora-release" , "fc" ) ) ; RETURN tmp CASE ! Empty( tmp := query_rpm( "suse-release" , "sus" ) ) ; RETURN tmp CASE ! Empty( tmp := query_rpm( "openSUSE-release" , "sus" ) ) ; RETURN tmp /* TODO: Rewrite this in Harbour */ CASE hb_FileExists( "/etc/pld-release" ) RETURN "" /* cat /etc/pld-release|sed -e '/1/ !d' -e 's/[^0-9]//g' -e 's/^/pld/'` */ ENDCASE RETURN StrTran( Lower( query_stdout( "uname -s" ) ), " ", "_" ) STATIC FUNCTION mk_extern_core() LOCAL aExtern IF GetEnvC( "HB_REBUILD_EXTERN" ) == "yes" .AND. ; ! Empty( GetEnvC( "HB_DYNLIB_BASE" ) ) /* FIXME: Use list of libs instead of dynamic lib */ IF ( aExtern := __hb_extern_get_list( hb_DirSepToOS( GetEnvC( "HB_DYNLIB_DIR" ) ) + hb_ps() + GetEnvC( "HB_DYNLIB_PREF" ) + GetEnvC( "HB_DYNLIB_BASE" ) + GetEnvC( "HB_DYNLIB_POST" ) + GetEnvC( "HB_DYNLIB_EXT" ) + GetEnvC( "HB_DYNLIB_PEXT" ) ) ) != NIL OutStd( "! Generating core extern headers..." + hb_eol() ) __hb_extern_gen( aExtern, "include" + hb_ps() + "hbscalar.hbx" ) __hb_extern_gen( aExtern, "include" + hb_ps() + "hbcpage.hbx" ) __hb_extern_gen( aExtern, "include" + hb_ps() + "hblang.hbx" ) __hb_extern_gen( aExtern, "include" + hb_ps() + "hbusrrdd.hbx" ) __hb_extern_gen( aExtern, "include" + hb_ps() + "harbour.hbx" ) RETURN .T. ENDIF ENDIF RETURN .F. STATIC FUNCTION GetEnvC( cEnvVar ) STATIC s_hEnvCache := { => } IF cEnvVar $ s_hEnvCache RETURN s_hEnvCache[ cEnvVar ] ENDIF RETURN s_hEnvCache[ cEnvVar ] := GetEnv( cEnvVar ) PROCEDURE mk_hbr( cDestDir ) LOCAL hAll := { => } LOCAL cDir := "contrib" + hb_ps() LOCAL aFile LOCAL cFileName FOR EACH aFile IN Directory( cDir + hb_osFileMask(), "D" ) IF aFile[ F_NAME ] == "." .OR. aFile[ F_NAME ] == ".." ELSEIF "D" $ aFile[ F_ATTR ] IF hb_FileExists( cFileName := cDir + aFile[ F_NAME ] + hb_ps() + aFile[ F_NAME ] + ".hbx" ) LoadHBX( cFileName, hAll ) ENDIF ENDIF NEXT hb_MemoWrit( hb_DirSepAdd( cDestDir ) + "contrib.hbr", hb_ZCompress( hb_Serialize( hAll ) ) ) RETURN STATIC FUNCTION LoadHBX( cFileName, hAll ) LOCAL cName := StrTran( cFileName, "\", "/" ) LOCAL cFile LOCAL pRegex LOCAL tmp LOCAL aDynamic := {} LOCAL cFilter IF ! Empty( cFile := hb_MemoRead( cFileName ) ) FOR EACH cFilter IN { ; "^DYNAMIC ([a-zA-Z0-9_]*)$", ; "ANNOUNCE ([a-zA-Z0-9_]*)$" } IF ! Empty( pRegex := hb_regexComp( cFilter, .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 NEXT ENDIF RETURN aDynamic #define _HB_FUNC_INCLUDE_ "HB_FUNC_INCLUDE" #define _HB_FUNC_EXCLUDE_ "HB_FUNC_EXCLUDE" #define _HB_SELF_PREFIX "__HBEXTERN__" #define _HB_SELF_SUFFIX "__" STATIC FUNCTION __hb_extern_get_list( cInputName ) LOCAL aExtern := NIL LOCAL hExtern LOCAL cStdOut, cStdErr LOCAL cTempFile LOCAL pRegex LOCAL aResult LOCAL tmp LOCAL cCommand LOCAL cRegex := "[\s]_?HB_FUN_([A-Z0-9_]*)[\s]" /* NOTE: non-gcc extractor configs don't support dynamic libs as input. */ DO CASE CASE "|" + GetEnv( "HB_COMPILER" ) + "|" $ "|gcc|mingw|mingw64|djgpp|" cCommand := "nm -g" + iif( GetEnv( "HB_PLATFORM" ) == "darwin", "", " --defined-only -C" ) + " {I}" CASE "|" + GetEnv( "HB_COMPILER" ) + "|" $ "|msvc|msvc64|pocc|pocc64|" IF "|" + GetEnv( "HB_COMPILER" ) + "|" $ "|msvc|msvc64|" cCommand := "dumpbin -symbols {I}" ELSE cCommand := "podump -symbols {I}" ENDIF cRegex := "SECT[0-9A-Z][0-9A-Z ].*[Ee]xternal.*_?HB_FUN_([A-Z0-9_]*)[\s]" CASE GetEnv( "HB_COMPILER" ) == "watcom" cCommand := "wlib {I}" CASE GetEnv( "HB_COMPILER" ) == "bcc" cCommand := "tlib {I}, {T}" CASE GetEnv( "HB_COMPILER" ) == "bcc64" cCommand := "tlib64 {I}, {T}" ENDCASE IF ! Empty( cCommand ) .AND. ; ! Empty( cRegex ) IF hb_FileExists( cInputName ) cCommand := StrTran( cCommand, "{I}", cInputName ) IF "{T}" $ cCommand FClose( hb_FTempCreateEx( @cTempFile,,, ".tmp" ) ) cCommand := StrTran( cCommand, "{T}", cTempFile ) ENDIF IF hb_processRun( cCommand,, @cStdOut, @cStdErr ) == 0 IF ! Empty( cTempFile ) cStdOut := MemoRead( cTempFile ) ENDIF IF ! Empty( pRegex := hb_regexComp( cRegex, .T., .T. ) ) aResult := hb_regexAll( pRegex, StrTran( cStdOut, Chr( 13 ) ),,,,, .T. ) aExtern := {} hExtern := { => } FOR EACH tmp IN aResult tmp[ 2 ] := hb_asciiUpper( tmp[ 2 ] ) IF !( tmp[ 2 ] $ hExtern ) AAdd( aExtern, tmp[ 2 ] ) hExtern[ tmp[ 2 ] ] := NIL ENDIF NEXT tmp := hb_cdpSelect( "EN" ) ASort( aExtern,,, {| tmp, tmp1 | tmp < tmp1 } ) hb_cdpSelect( tmp ) ENDIF ENDIF IF ! Empty( cTempFile ) FErase( cTempFile ) ENDIF ENDIF ENDIF RETURN aExtern STATIC PROCEDURE __hb_extern_get_exception_list( cInputName, /* @ */ aInclude, /* @ */ aExclude, /* @ */ hDynamic ) LOCAL cFile LOCAL pRegex LOCAL tmp aInclude := {} aExclude := {} hDynamic := { => } IF ! Empty( cFile := MemoRead( cInputName ) ) IF ! Empty( pRegex := hb_regexComp( "[\s]" + _HB_FUNC_INCLUDE_ + "[\s]([a-zA-Z0-9_].[^ \t\n\r]*)", .T., .T. ) ) FOR EACH tmp IN hb_regexAll( pRegex, StrTran( cFile, Chr( 13 ) ),,,,, .T. ) AAdd( aInclude, tmp[ 2 ] ) NEXT ENDIF IF ! Empty( pRegex := hb_regexComp( "[\s]" + _HB_FUNC_EXCLUDE_ + "[\s]([a-zA-Z0-9_].[^ \t\n\r]*)", .T., .T. ) ) FOR EACH tmp IN hb_regexAll( pRegex, StrTran( cFile, Chr( 13 ) ),,,,, .T. ) AAdd( aExclude, tmp[ 2 ] ) NEXT ENDIF IF ! Empty( pRegex := hb_regexComp( "^DYNAMIC ([a-zA-Z0-9_]*)$", .T., .T. ) ) FOR EACH tmp IN hb_regexAll( pRegex, StrTran( cFile, Chr( 13 ) ),,,,, .T. ) hDynamic[ Upper( tmp[ 2 ] ) ] := tmp[ 2 ] NEXT ENDIF ENDIF RETURN STATIC FUNCTION __hb_extern_gen( aFuncList, cOutputName ) LOCAL aExtern LOCAL cExtern LOCAL tmp LOCAL aInclude LOCAL aExclude LOCAL hDynamic LOCAL cSelfName := _HB_SELF_PREFIX + Upper( hb_FNameName( cOutputName ) ) + _HB_SELF_SUFFIX LOCAL cLine := "/* " + Replicate( "-", 68 ) + hb_eol() LOCAL cHelp := ; " * Syntax: // HB_FUNC_INCLUDE " + hb_eol() + ; " * // HB_FUNC_EXCLUDE " + hb_eol() + ; " */" + hb_eol() __hb_extern_get_exception_list( cOutputName, @aInclude, @aExclude, @hDynamic ) cExtern := "" IF Empty( aInclude ) .AND. ; Empty( aExclude ) cExtern += ; cLine + ; " * NOTE: You can add manual override which functions to include or" + hb_eol() + ; " * exclude from automatically generated EXTERNAL/DYNAMIC list." + hb_eol() + ; cHelp ELSE cExtern += ; cLine + ; " * NOTE: Following comments are control commands for the generator." + hb_eol() + ; " * Do not edit them unless you know what you are doing." + hb_eol() + ; cHelp IF ! Empty( aInclude ) cExtern += hb_eol() FOR EACH tmp IN aInclude cExtern += "// " + _HB_FUNC_INCLUDE_ + " " + tmp + hb_eol() NEXT ENDIF IF ! Empty( aExclude ) cExtern += hb_eol() FOR EACH tmp IN aExclude cExtern += "// " + _HB_FUNC_EXCLUDE_ + " " + tmp + hb_eol() NEXT ENDIF ENDIF cExtern += ; hb_eol() + ; cLine + ; " * WARNING: Automatically generated code below. DO NOT EDIT! (except casing)" + hb_eol() + ; " * Regenerate with HB_REBUILD_EXTERN=yes build option." + hb_eol() + ; " */" + hb_eol() + ; hb_eol() + ; "#ifndef " + "__HBEXTERN_CH__" + Upper( hb_FNameName( cOutputName ) ) + "__" + hb_eol() + ; "#define " + "__HBEXTERN_CH__" + Upper( hb_FNameName( cOutputName ) ) + "__" + hb_eol() + ; hb_eol() + ; "#if defined( __HBEXTREQ__ ) .OR. defined( " + cSelfName + "ANNOUNCE" + " )" + hb_eol() + ; " ANNOUNCE " + cSelfName + hb_eol() + ; "#endif" + hb_eol() + ; hb_eol() + ; "#if defined( __HBEXTREQ__ ) .OR. defined( " + cSelfName + "REQUEST" + " )" + hb_eol() + ; " #command DYNAMIC => EXTERNAL " + hb_eol() + ; "#endif" + hb_eol() + ; hb_eol() IF Empty( aInclude ) aExtern := aFuncList ELSE aExtern := {} FOR EACH tmp IN aFuncList IF AScan( aInclude, {| flt | hb_WildMatchI( flt, tmp, .T. ) } ) > 0 AAdd( aExtern, tmp ) ENDIF NEXT ENDIF FOR EACH tmp IN aExtern IF ! hb_WildMatch( "HB_GT_*_DEFAULT", tmp, .T. ) .AND. ; ! hb_WildMatch( _HB_SELF_PREFIX + "*" + _HB_SELF_SUFFIX, tmp, .T. ) .AND. ; AScan( aExclude, {| flt | hb_WildMatchI( flt, tmp, .T. ) } ) == 0 cExtern += "DYNAMIC " + hb_HGetDef( hDynamic, tmp, tmp ) + hb_eol() ENDIF NEXT cExtern += ; hb_eol() + ; "#if defined( __HBEXTREQ__ ) .OR. defined( " + cSelfName + "REQUEST" + " )" + hb_eol() + ; " #uncommand DYNAMIC => EXTERNAL " + hb_eol() + ; "#endif" + hb_eol() + ; hb_eol() + ; "#endif" + hb_eol() RETURN hb_MemoWrit( cOutputName, cExtern )