Página 1 de 1

Configuração de compilação

Enviado: 17 Fev 2025 12:37
por JoséQuintas
Meu uso de harbour é fora do normal, mas é tudo simples.
Vamos no passo a passo.

Salvo sempre o harbour em d:\harbour
Salvo sempre o mingw em d:\harbour\comp\mingw32
Salvo sempre hwgui em d:\github\hwgui
Salvo sempre hmg3 em d:\github\hmg3
Salvo sempre hmg extended em d:\github\hmge
Salvo sempre oohg em d:\github\oohg
Salvo sempre fivewin em d:\github\fivewin

Nada de incomum, cada coisa numa pasta.
Se estivesse em harbour\addons simplificaria um pouquinho
Mas gosto de deixar o harbour livre, posso apagar o harbour e colocar outro no lugar.
Se salvar as libs em addons, ao apagar o harbour as libs também serão apagadas.

A sefazclass, salvo em d:\fontes\integra\sefazclass
e minha lib, salvo em d:\fontes\integra\libjpa
Só pra facilitar pesquisas.
a libjpa inclui outra versão da pdfclass, rmchartclass, e outras coisas.
Fontes de aplicativo ficam em d:\fontes\nome ou d:\fontes\testes
o git/github controla certinho, um projeto não se mistura com outro, mesmo que esteja em uma subpasta de outro projeto.

Tem também o dlgauto, ele faz parte do aplicativo, salvo em d:\github\dlgauto

Ok, normal, cada coisa na sua pasta.

Configuração de compilação

Enviado: 17 Fev 2025 12:40
por JoséQuintas
Primeira configuração: sistema operacional

É só o Path do harbour e do compilador C.
Isso é necessário pra compilação

PATH=d:\harbour\bin;d:\harbour\comp\mingw32\bin;d:\tools\util

Também configuro as variáveis pra geração do harbour.
Não precisa pra compilação, mas fica tudo pronto.

a pasta tools\util é porque o UPX não faz parte do harbour, fica separado, pra compactar.

Só isso no sistema operacional.

Configuração de compilação

Enviado: 17 Fev 2025 12:52
por JoséQuintas
Default do harbour: d:\harbour\bin\hbmk.hbc

Compilo sempre igual, pra que inventar moda, já fica o harbour configurado.

Código: Selecionar todos

mt=yes
gui=yes
strip=yes
fullstatic=yes
PRGFLAGS=-m -n -w3 -es2 -ge1 -DMT_EXPERIMENTAL -DHB_NO_GTGUI=YES
libpaths=d:/fontes/integra/libjpa
libpaths=d:/fontes/integra/boletoclass
libpaths=d:/fontes/integra/sefazclass
libpaths=d:/github/rmchartclass
libpaths=d:/github/wvgtest
libpaths=d:/github/hwgui
libpaths=d:/github/oohg
libpaths=d:/github/hmge
libpaths=d:/github/hmg3
libpaths=d:/github/fivewin
incpaths=d:/fontes/util/build
Isso vale pra tudo que eu compilar com hbmk2.

mt=yes
Sempre compilo com multithread, já fica fixo

gui=yes
Não uso console pra nada, nem pra teste.
Isso indica que o aplicativo é GUI

strip=yes
Isso é pra mingw, o EXE fica menor, não tem nada a ver com compactação

fullstatic=yes
Isso é pra não criar nada em DLL. Pra Linux é muito importante. Pra Windows é só pra garantir.

PRGFLAGS=-m -n -w3 -es2 -ge1 -DMT_EXPERIMENTAL -DHB_NO_GTGUI=YES
Isso é pra HWGUI, desse jeito gera HWGUI diferente um pouco.

libpaths=d:/fontes/integra/libjpa
libpaths=d:/fontes/integra/boletoclass
libpaths=d:/fontes/integra/sefazclass
libpaths=d:/github/rmchartclass
libpaths=d:/github/wvgtest
libpaths=d:/github/hwgui
libpaths=d:/github/oohg
libpaths=d:/github/hmge
libpaths=d:/github/hmg3
libpaths=d:/github/fivewin
incpaths=d:/fontes/util/build

Isso tudo são só pastas.
Comportamento parecido com o SET PATH so sistema operacional.
Se não encontrar algo na pasta atual, vai procurar em alguma dessas pastas.
Isso não altera nada na compilação, nada dessas pastas vai entrar, a não ser que a compilação peça pra incluir alguma coisa.

hbmk2 test.prg

Isso vai compilar test.prg, vai ser multithread, vai compactar, e vai ser em modo GUI - não console.
Vai entrar a LIB padrão do harbour pra GUI, que não é GTWVG, é outra.

Ok até aqui ?
Defini um padrão de compilação, e defini aonde buscar arquivos, caso não encontre nas pastas normais.
Não disse pra acrescentar nenhuma lib por conta própria.

Configuração de compilação

Enviado: 17 Fev 2025 13:10
por JoséQuintas
Aí que a coisa fica legal.

hbmk2 test.prg
hbmk2 test.prg hwgui.hbc
hbmk2 test.prg hmge.hbc
hbmk2 test.prg hmg3.hbc
hbmk2 test.prg fivewin.hbc
hbmk2 test.prg oohg.hbc
hbmk2 test.prg gtwvg.hbc

O que acontece agora ?
O hbmk2 vai procurar esses arquivos em alguma pasta indicada lá.
hwgui.hbc, vai encontrar esse arquivo na pasta d:\github\hwgui e vai usar, e isso já configura pra hwgui.
E o mesmo acontece nas outras linhas contendo hwgui.hbc, hmge.hbc, hmg3.hbc, fivewin.hbc, oohg.hbc, gtwvg.hbc

OK ?
Usar qualquer lib a qualquer momento.
As únicas coisas que fiz foi: configurar path pra harbour e mingw, e criar o arquivo hbmk.hbc

Lógico.....
As libs originais podem ou não ter o hbc delas.
Aqui eu criei pra todas.

hbc é um arquivo aonde a gente coloca o que precisa pra poder compilar.
criei o harbour\bin\hbmk.hbc que contém o padrão.
Eles são cumulativos.
Em hwgui.hbc, por exemplo, nele indica aonde estão os arquivos CH da hwgui, e as libs da hwgui que precisam entrar no EXE pra hwgui funcionar.
E o mesmo no hbc das outras libs.

É só isso.
Se usa mais coisas, de outras libs, é só acrescentar, porque não dá pra fazer adivinhação.
usa pdf ? acrescenta hbhpdf.hbc
usa zip ? acrescenta hbziparc.hbc ou equivalente
usa função do Windows ? acrescenta hbwin.hbc

Compilação é isso.
É colocar a lista do que entra no seu projeto.
E hbc é isso: se hwgui tem arquivos CH e arquivos de LIB, é indicar as pastas aonde encontrar, e o nome das LIBs.

Vantagem do hbc: não ficar repetindo a mesma coisa toda hora.
Você tem lá 10 linhas que SEMPRE que vai compilar com minigui precisa daquelas linhas. coloque num arquivo minigui.hbc
Pra que repetir as 10 linhas em dezenas de projetos, se pode colocar apenas minigui.hbc

Não precisa IDE pra compilar, não precisa builder pra compilar, não precisa BAT pra compilar, só precisa de um HBC.
O hbc vai dizer tudo que precisa.

Lógico...
Num aplicativo entram vários fontes, e podem entrar LIBs adicionais além das básicas, e resource, e manifest, etc.
Nesse caso vai usar o HBP e colocar lá a parte diferente.
Milagre não dá pra fazer.

Configuração de compilação

Enviado: 17 Fev 2025 13:19
por JoséQuintas
E eu criei um build.prg
Ele é chamado antes do hbmk2.

O que o build.exe faz ?
Coloquei nele pra conferir toda minha configuração, acrescentar se faltar alguma coisa
Mas principalmente, coloquei alguns dos meus defaults, que não dava pra configurar no harbour.
Só uma ajuda extra.

E compilo tudo digitando C <ENTER>
Mesmo que seja só pra não ter que digitar hbmk2 *.hbp, já vale a pena, digitar uma letra ao invés de várias.

Sei lá... é tão simples compilar, não sei porque tantos se confundem.

Se tá esquecendo os comandos....
Tudo bem, crie um build.prg que nem eu, e coloque lá os comandos.
Coloque lá também pra ele configurar a máquina pra você.

Mesmo que esqueça os comandos, se olhar o fonte do build.prg vai lembrar de tudo.
O fonte do build vai mostrar como configura máquina, como configura harbour, e também vai poder configurar pra você.

É simples assim.

Também pode fazer mais avançado, de repente capturar as mensagens de erro, e mostrar soluções conforme o erro.
Isso é possível, o HBMK2 faz algo sobre isso, e dá pra fazer mais, se quiser.


Voltando ao build.prg:

Eu não disse que é configurar o path pra harbour e mingw ?
Então, meu build verifica se os paths estão configurados, e se está encontrando harbour e mingw no path

Eu não disse que uso aquele hbmk.hbc ?
Então, meu build verifica se ele está lá, se tem aquelas linhas nele, e cria caso não exista.

Com tudo configurado, não é só digitar hbmk2 *.hbp ?
Então, é o que meu build faz

Se eu estiver compilando na pasta samples do fivewin..... só pode ser exemplo fivewin... eu teria que acrescentar fivewin.hbc
O mesmo na pasta samples das outras LIBs.
Então, é o que meu build faz. Se estou na pasta samples de alguma lib, ele já acrescenta o hbc da lib.

Qualquer um pode fazer isso, apenas nunca pensou em fazer.

E o build ? atrapalha na compilação ? usa memória por exemplo ?
Não
Uso um velho recurso de arquivo BAT, que é reescrever as linhas.

c.bat
@echo off
d:\fontes\build\build.exe
xxxxxxx

O build.exe reescreve a linha que vém depois

Código: Selecionar todos

cTxt := "@echo off" + hb_Eol()
cTxt += "d:\fontes\build\build.exe %*" + hb_Eol()
cTxt += "hbmk2 *.hbp" + hb_Eol() // exemplo
A compilação vai ser executada sem nenhum programa carregado na memória.

Também acrescento no build.exe pra ver se são os programas que faço assinatura digital no EXE, e outras coisas mais.
Ele vai acrescentando meu dia a dia automaticamente, pra assinar o EXE por exemplo.
Assim não esqueço nunca.

Configuração de compilação

Enviado: 17 Fev 2025 13:53
por JoséQuintas
Meu build também assina o harbour.exe e o hbmk2.exe

Teve uma época que isso alterava em muito a compilação, deixando muito mais rápido.
Senão, a cada fonte compilado era um teste de vírus encima do EXE.
Nunca mais testei, apenas continuo assinando.

Configuração de compilação

Enviado: 17 Fev 2025 14:01
por developer
José, antes de mais nada, obrigado por compartilhar seu "modus operandi".
Não precisa IDE pra compilar, não precisa builder pra compilar, não precisa BAT pra compilar...
O que você faz é 100% baseado na ferramenta hbmk2 do Viktor Szakats que é uma baita contribuição para o Harbour, realmente precisamos agradecer a ele pela excelente ferramenta.

Vou aproveitar e fazer umas perguntas para aprender.
É só o Path do harbour e do compilador C.
Isso é necessário pra compilação

PATH=d:\harbour\bin;d:\harbour\comp\mingw32\bin;d:\tools\util
Por que você precisa adicionar o path do compilador C? Normalmente não é necessário já que ele pode ser autodetectado. Talvez porque você propositalmente coloque em uma pasta diferente?


Também configuro as variáveis pra geração do harbour.
Não precisa pra compilação, mas fica tudo pronto.
Você poderia mostrar que variáveis você configura e qual é a configuração, por favor?


a pasta tools\util é porque o UPX não faz parte do harbour, fica separado, pra compactar.
É somente por causa do UPX? Prefere deixar o UPX numa pasta diferente por algum motivo especial? Normalmente fica na pasta \harbour\bin o que remove a necessidade de adicionar um caminho extra no PATH, assim como você já faz com o \harbour\bin\hbmk.hbc


E eu criei um build.prg
Ele é chamado antes do hbmk2.

O que o build.exe faz ?
Coloquei nele pra conferir toda minha configuração, acrescentar se faltar alguma coisa
Mas principalmente, coloquei alguns dos meus defaults, que não dava pra configurar no harbour.
Só uma ajuda extra.
...
Se tá esquecendo os comandos....
Tudo bem, crie um build.prg que nem eu, e coloque lá os comandos.
Coloque lá também pra ele configurar a máquina pra você.

Mesmo que esqueça os comandos, se olhar o fonte do build.prg vai lembrar de tudo.
O fonte do build vai mostrar como configura máquina, como configura harbour, e também vai poder configurar pra você.

É simples assim.
Opa, este parece ser interessante, você compartilha o build.prg? Para eu ver o que faz e quem sabe eu posso aproveitar para usar aqui também? Ajuda extra sempre é bem-vinda.


E compilo tudo digitando C <ENTER>
Mesmo que seja só pra não ter que digitar hbmk2 *.hbp, já vale a pena, digitar uma letra ao invés de várias.
Esse também é interessante. O que tem no C? Simplesmente o conteúdo abaixo ou tem algo mais? (acho que pelo build.prg dá para saber isso também).

Código: Selecionar todos

@echo off
d:\fontes\build\build.exe
hbmk2 *.hbp

Assim não esqueço nunca.
Isso ajuda muito mesmo, obrigado por compartilhar o seu processo de trabalho.

Configuração de compilação

Enviado: 17 Fev 2025 15:50
por JoséQuintas
Algumas coisas pode ser por costume.
O hbmk2 detecta o compilador que estiver no PATH, não lembro se na pasta COMP ele detecta automático.
Eventualmente, se tivermos mais de um e quisermos um específico, dá pra indicar também HB_COMPILER=mingw ou mingw64

Na prática, a pasta \tools\util tem mais coisas: UPX, editor de textos, c.bat, e outros.
Aliás.... renomeei o UPX.EXE e coloquei outro no lugar, pra alterar os parâmetros.

Outro detalhe: ao mudar de projeto limpo a pasta temp.
Supondo dois arquivos de teste, contendo test.prg, nomes iguais mas conteúdo diferente.
Uso -workdir=c:\temp

O bat é só aquilo mesmo.
O build.exe vai alterar o conteúdo após a chamada.

Código: Selecionar todos

/*
BUILD - PRE-COMPILACAO
José Quintas
*/

ANNOUNCE HB_GTSYS
REQUEST errorsys

#include "directry.ch"

STATIC stErro := .F.

FUNCTION Main( ... )

   LOCAL aParamList, aSignList := {}, cDirMask, aCmdList := {}

   SetMode( 33, 100 )
   SetColor( "W/B" )
   FOR EACH cDirMask IN { "ze_resource.*", "*.reso", "_hbmkaut*.*" }
      AEval( Directory( "c:\temp\" + cDirMask ), { | e | fErase( "c:\temp\" + e[ F_NAME ] ) } )
   NEXT
   aParamList := hb_aParams()
   CheckGetEnv( @aCmdList )
   CheckPath( @aSignList, @aCmdList )
   checkHbmkHbc()
   CheckBuild()
   WriteBat( aParamList, aSignList, aCmdList )
   IF stErro
      Inkey(3)
   ENDIF

   RETURN Nil

STATIC FUNCTION WriteBat( aParamList, aSignList, aCmdList )

   LOCAL oElement, cPath, cCmdDefault := "", cCmd := "", aHbpList := {}, aList, cItem
   LOCAL cBatFile := "d:\tools\util\c.bat", cFile, aFile, cHbp, lMultiHbp := .F.

   cCmd := hb_ProgName() + " %*" + hb_Eol()
   FOR EACH cItem IN aCmdList
      cCmd += cItem + hb_Eol()
   NEXT

   cPath := Upper( hb_cwd() )
   IF ! Empty( aSignList )
      FOR EACH cFile IN aSignList
         cCmd += "call assina " + cFile + hb_Eol()
      NEXT
   ENDIF

   IF Len( aParamList ) != 0 .AND. aParamList[ 1 ] == "/cmd"
      hb_ADel( aParamList, 1, .T. )
   ELSE
      IF hb_AScan( aParamList, { | e | e $ "|-w0|-w1|-w2|-w3|"  } ) == 0
         AAdd( aParamList, "-w3" )
      ENDIF
      IF hb_AScan( aParamList, { | e | e $ "|-es0|-es1|-es2|" } ) == 0
         AAdd( aParamList, "-es2" )
      ENDIF
      IF hb_AScan( aParamList, { | e | e == "-m" } ) == 0
         AAdd( aParamList, "-m" )
      ENDIF
      IF hb_ASCan( aParamList, { | e | e == "-n" } ) == 0
         AAdd( aParamList, "-n" )
      ENDIF
      //IF ASCan( aParamList, "-gc3" ) == 0
      //   AAdd( aParamList, "-gc3" )
      //ENDIF
      IF Len( Directory( "*.hbp" ) ) != 0
         aList := Directory( "*.hbp" )
         FOR EACH aFile IN aList
            IF Lower( aFile[ F_NAME ] ) != "hwguidyn.hbp" // error IF create it
               AAdd( aHbpList, aFile[ F_NAME ] )
            ENDIF
         NEXT
      ELSEIF Len( Directory( "*.prg" ) ) != 0
         AAdd( aParamList, "*.prg" )
         AAdd( aParamList, "*.rc" )
      ELSE
         ShowNormal( hb_cwd() )
      ENDIF
   ENDIF
   AAdd( aParamList, "-strip" )
   AAdd( aParamList, "-compr" )
   AAdd( aParamList, "-workdir=c:\temp" )
   AAdd( aParamList, "-q" )
   AAdd( aParamList, "-I" + hb_FNameDir( hb_ProgName() ) )
   IF "SAMPLE" $ Upper( hb_cwd() )
      IF "HMGE" $ Upper( hb_cwd() )
         AAdd( aParamList, "hmge.hbc" )
      ENDIF
      IF "HWGUI" $ Upper( hb_cwd() )
         AAdd( aParamList, "hwgui.hbc" )
      ENDIF
      IF "OOHG" $ Upper( hb_cwd() )
         AAdd( aParamList, "oohg.hbc" )
      ENDIF
      IF "FIVEWIN" $ Upper( hb_cwd() )
         AAdd( aParamList, "fivewin.hbc" )
      ENDIF
   ENDIF
   FOR EACH oElement IN aParamList
      cCmdDefault += oElement + " "
   NEXT
   IF Len( aHbpList ) == 0
      cCmd += "HBMK2 " + cCmdDefault + hb_Eol()
   ELSE
      IF Len( aHbpList ) > 1
         lMultiHbp := .T.
      ENDIF
      FOR EACH cHbp IN aHbpList
         IF lMultiHbp
            //cCmd += "ECHO S | DEL C:\TEMP\*.*" + hb_Eol()
         ENDIF
         IF "-hbcontainer" $ MemoRead( cHbp ) .AND. ! "-rebuildall" $ cCmdDefault
            cCmdDefault += " -rebuildall"
         ENDIF
         cCmd += "HBMK2 " + cHbp + " " + cCmdDefault + hb_Eol()
      NEXT
   ENDIF
   DO CASE
   CASE "\SJPA\"     $ cPath; cCmd += "if exist ..\sjpa.exe call assina.bat ..\sjpa.exe" + hb_Eol()
   CASE "\HAROLDO\"  $ cPath; cCmd += "if exist hl.exe      call assina.bat hl.exe"      + hb_Eol()
   CASE "\INTEGRA\"  $ cPath; cCmd += "if exist jpa.exe     call assina.bat jpa.exe"     + hb_Eol()
   CASE "\BUILD\"    $ cPath; cCmd += "if exist build.exe call assina.bat build.exe"   + hb_Eol()
   CASE "\UTIL\UPX\" $ cPath
      cCmd += "if exist pupx.exe  call assina.bat pupx.exe" + hb_Eol()
      cCmd += "if exist pupx.exe copy pupx.exe \tools\util\upx.exe" + hb_Eol()
   ENDCASE
   IF ! hb_DirExists( "c:\temp" )
      hb_DirCreate( "c:\temp" )
      ShowAlert( "Created c:\temp" )
   ENDIF
   hb_MemoWrit( cBatFile, cCmd )

   RETURN Nil

STATIC FUNCTION CheckHbmkHbc()

   LOCAL lUpdate := .F., cParam, cTxt := "", cFileHbmk, cPath
   LOCAL cLib1 := "", cLib2, cPathLib := "d:\harbour\lib\win\mingw\"
   LOCAL aParamList := { ;
      "mt=yes", ;
      "gui=yes", ;
      "strip=yes", ;
      "fullstatic=yes", ;
      ; // "{hbexe}compr=yes", ;
      "PRGFLAGS=-m -n -w3 -es2 -ge1 -DMT_EXPERIMENTAL -DHB_NO_GTGUI=YES", ; // -DHB_NO_HWGUIDEBUG=YES", ;
      "incpaths=d:/fontes/util/build", ;
      "libpaths=d:/fontes/integra/libjpa", ;
      "libpaths=d:/fontes/integra/boletoclass", ;
      "libpaths=d:/fontes/integra/sefazclass", ;
      "libpaths=d:/github/rmchartclass", ;
      "libpaths=d:/github/wvgtest", ;
      "libpaths=d:/github/hwgui", ;
      "libpaths=d:/github/oohg", ;
      "libpaths=d:/github/hmge", ;
      "libpaths=d:/github/hmg3", ;
      "libpaths=d:/github/fivewin" }

   //"PRGFLAGS=-m -n -w3 -es2 -ge1 -DHB_VER_REVID=1" }
   //"{mingw}CFLAGS=" + ;
   //" -Wno-implicit-fallthrough" + ;
   //" -Wno-cast-function-type" + ;
   //" -Wno-misleading-indentation",

   cPath := CheckFileOnPath( "hbmk2.exe" )
   IF Empty( cPath )
      ShowAlert( "hbmk2.exe not found on PATH to check hbmk.hbc" )
      RETURN Nil
   ENDIF
   IF Right( cPath, 1 ) != "\"
      cPath += "\"
   ENDIF
   cFileHbmk := cPath + "hbmk.hbc"
   IF File( cFileHbmk )
      cTxt := MemoRead( cFileHbmk )
      IF Right( cTxt, 2 ) != hb_Eol()
         cTxt += hb_Eol()
      ENDIF
   ENDIF
   IF "xharbour" $ Lower( cPath  )
      AAdd( aParamList, "-xhb" )
   ENDIF
   FOR EACH cParam IN aParamList
      IF ! cParam $ cTxt
         cTxt += cParam + hb_Eol()
         ShowAlert( "hbmk.hbc adding " + cParam )
         stErro  := .T.
         lUpdate := .T.
      ENDIF
   NEXT
   IF lUpdate
      hb_MemoWrit( cFileHbmk, cTxt )
   ENDIF
   IF File( cPathLib + "libforcedebug.a" )
      cLib1 := MemoRead( cPathLib + "libforcedebug.a" )
   ENDIF
   cLib2 := MemoRead( cPathLib + "libhbdebug.a" )
   IF ! cLib1 == cLib2
      ShowAlert( "libforcedebug.a not found or invalid" )
      hb_MemoWrit( cPathLib + "libforcedebug.a", cLib2 )
   ENDIF

   RETURN Nil

STATIC FUNCTION CheckGetEnv( aCmdList )

   LOCAL oElement
   LOCAL aList := { ;
      { "HB_BUILD_DYN",         "no" }, ;
      { "HB_BUILD_CONTRIB_DYN", "no" }, ;
      { "HB_BUILD_STRIP",       "all" }, ;
      { "HB_BUILD_SHARED",      "no" }, ;
      { "HB_COMPILER",          "mingw" }, ;
      { "HB_INSTALL_PREFIX",    "d:\harbour" }, ;
      { "HB_LANG",              "EN" } }

   // { "HB_USER_CFLAGS", "-DHB_GUI -HB_NO_PROFILER _HB_NO_TRACE" }
   // { "HB_USER_CFLAGS",       ["-Wno-implicit-fallthrough -Wno-reserved-identifier -Wno-used-but-marked-unused"] } }
   //{ "HB_BUILD_MODE",        "cpp" } }
   //      { "HB_USER_CFLAGS",       "-Wno-null-dereference -Wno-cast-function-type -Wno-return-local-addr" }  }

   // win_Reg fail
   FOR EACH oElement IN aList
      IF Empty( win_RegRead( "HKCU\Environment\" + oElement[1] ) ) ;
            .OR. ! win_RegRead( "HKCU\Environment\" + oElement[1] ) == oElement[2] ;
            .OR. Empty( GetEnv( oElement[ 1 ] ) ) ;
            .OR. ! GetEnv( oElement[ 1 ] ) == oElement[ 2 ]
         ShowAlert( "Not found SET " + oElement[ 1 ] + "=" + oElement[ 2 ] )
         ShellExecuteOpen( "setx", oElement[ 1 ] + " " + oElement[ 2 ],, 0 )
         win_RegWrite( "HKCU\Environment\" + oElement[1], oElement[2] )
         AAdd( aCmdList, "SET " + oElement[ 1 ] + " " + oElement[2] )
      ENDIF
   NEXT

   RETURN Nil

STATIC FUNCTION CheckPath( aSignList, aCmdList )

   LOCAL cPath, aPathList, lChanged := .F., cPathFile, cFile, cItem

   cPath := win_RegRead( "HKCU\Environment\Path" )
   hb_Default( @cPath, "" )

   aPathList := hb_RegExSplit( ";", cPath )
   FOR EACH cPath IN { ;
         "d:\harbour\bin", ;
         "d:\harbour\comp\mingw32\bin", ;
         "d:\tools\util" }
      IF ASCan( aPathList, { | e | Lower( cPath ) $ Lower( e ) } ) == 0
         ShowAlert( "Adding PATH " + cPath )
         AAdd( aPathList, cPath )
         AAdd( aCmdList, "SET PATH=%PATH%;" + cPath )
         lChanged := .T.
      ENDIF
   NEXT
   IF lChanged
      cPath := ""
      FOR EACH cItem IN aPathList
         cPath += iif( cItem:__EnumIndex() == 1, ";", "" ) + cItem
      NEXT
      win_RegWrite( "HKCU\Environment\Path", cPath )
      // ShellExecuteOpen( "setx", [PATH "] + + cPath + ["] )
   ENDIF

   FOR EACH cFile IN { "c.bat" }
      IF Empty( CheckFileOnPath( cFile ) )
         ShowAlert( cFile + " not in PATH" )
         ShowAlert( "Remember run build.exe as administrator from explorer, and re-open cmd window" )
      ENDIF
   NEXT
   FOR EACH cFile IN { "hbmk2.exe", "harbour.exe", "upx.exe" } // "upx.exe", "mingw32-make.exe", "gcc.exe" }
      cPathFile := CheckFileOnPath( cFile )
      IF Empty( cPathFile )
         ShowAlert( cFile + " not in PATH" )
      ELSEIF ! TestSignedEXE( cPathFile + cFile )
         AAdd( aSignList, cPathFile + cFile )
         ShowAlert( cPathFile + cFile + " not signed" )
      ENDIF
   NEXT

   RETURN Nil

STATIC FUNCTION CheckFileOnPath( cFile )

   LOCAL cPath, cPathFile

   cFile := Lower( cFile )
   FOR EACH cPath IN hb_RegExSplit( ";", GetEnv( "PATH" ) )
      IF Right( cPath, 1 ) != "\"
         cPath := cPath + "\"
      ENDIF
      IF File( cPath + cFile )
         cPathFile := cPath
         EXIT
      ENDIF
   NEXT

   RETURN cPathFile

STATIC FUNCTION CheckBuild()

   LOCAL cDateTime, cTxt, cFileName, hSetup, cLastPath, aItem
   LOCAL aList := { ;
      { "LastPath", "" }, ;
      { "LastBuildDate", "" }, ;
      { "Total", 0 }, ;
      { "Year", 0 }, ;
      { "Month", 0 }, ;
      { "Day", 0 } }

   AAdd( aList, { Left( Dtos( Date() ), 4 ), 0 } )
   AAdd( aList, { Left( Dtos( Date() ), 4 ) + " Max", 0 } )
   AAdd( aList, { Left( Dtos( Date() ), 6 ), 0 } )
   AAdd( aList, { Left( Dtos( Date() ), 6 ) + " Max", 0 } )
   AAdd( aList, { Dtos( Date() ), 0 } )

   cFileName := hb_FNameDir( hb_ProgName() ) + hb_FNameName( hb_ProgName() )
   hSetup    := hb_JsonDecode( MemoRead( cFileName + ".json" ) )
   IF ValType( hSetup ) != "H"
      hSetup := hb_Hash()
   ENDIF
   FOR EACH aItem IN aList
      IF ! hb_HHasKey( hSetup, aItem[ 1 ] )
         hb_HSet( hSetup, aItem[ 1 ], aItem[ 2 ] )
      ENDIF
   NEXT

   cDateTime := Dtos( Date() ) + Substr( Time(), 1, 2 ) + Substr( Time(), 4, 2 )
   cLastPath := hSetup[ "LastPath" ]

   IF Day( Date() ) != Day( Stod( hSetup[ "LastBuildDate" ] ) )
      hSetup[ "Day" ] := 0
   ENDIF
   IF Month( Date() ) != Month( Stod( hSetup[ "LastBuildDate" ] ) )
      hSetup[ "Month" ] := 0
   ENDIF
   IF Year( Date() ) != Year( Stod( hSetup[ "LastBuildDate" ] ) )
      hSetup[ "Year" ] := 0
   ENDIF
   hSetup[ "Total" ] += 1
   hSetup[ "Year" ]  += 1
   hSetup[ "Month" ] += 1
   hSetup[ "Day" ]   += 1
   hSetup[ "LastPath" ]   := hb_cwd()
   hSetup[ "LastBuildDate" ] := Dtos( Date() )
   hSetup[ Left( Dtos( Date() ), 4 ) ] += 1
   hSetup[ Left( Dtos( Date() ), 6 ) ] += 1
   hSetup[ Dtos( Date() ) ] += 1

   Reorganize( @hSetup )

   hb_MemoWrit( cFileName + ".json", hb_JsonEncode( hSetup, .T. ) )

   IF ! Upper( cLastPath )  == Upper( hb_cwd() )
      DeleteContent( "c:\temp", .F. )
   ENDIF

   cTxt := "#define JOSEQUINTAS_VERSAO    " + ["]  + Transform( cDateTime, "@R 9999.99.99.9999" ) + ["] + hb_Eol()
   cTxt += "#define JOSEQUINTAS_VERSAO_RC  " + Transform( Substr( cDateTime, 3 ), "@R 9999,99,99,99" ) + hb_Eol()
   hb_MemoWrit( cFileName + ".ch", cTxt )
   IF File( "build.ch" ) // save on folder too, IF have it
      hb_MemoWrit( "build.ch", cTxt )
   ENDIF
   AEval( Directory( "*.upx" ), { | e | fErase( e[ F_NAME ] ) } ) // temporary upx

   RETURN Nil

STATIC FUNCTION DeleteContent( cFolder, lDeleteFolder )

   LOCAL oFiles, oFile, lDelete

   hb_Default( @lDeleteFolder, .F. )

   ShowNormal( "Delete on  " + cFolder )
   oFiles := Directory( cFolder + "\*.*", "D" )
   FOR EACH oFile IN oFiles
      IF "D" $ oFile[ F_ATTR ]
         IF oFile[ F_NAME ] != "." .AND. oFile[ F_NAME ] != ".."
            DeleteContent( cFolder + "\" + oFile[ F_NAME ], .T. )
         ENDIF
      ELSE
         lDelete := .T.
         DO CASE
         CASE hb_FNameExt( oFile[ F_NAME ] ) == ".c"
         CASE hb_FNameExt( oFile[ F_NAME ] ) == ".o"
         CASE ASCan( { ".PRG", ".DBF", ".CH", ".HBP", ".RC" }, { | e | e == Upper( hb_FNameExt( oFile[ F_NAME ] ) ) } ) != 0
            lDelete := .F.
         CASE oFile[ F_DATE ] != Date()
         CASE Left( oFile[ F_TIME ], 4 ) != Left( Time(), 4 )
         OTHERWISE
            lDelete := .F.
         ENDCASE
         IF lDelete
            ShowNormal( "Deleting " + cFolder + "\" + oFile[ F_NAME ] )
            fErase( cFolder + "\" + oFile[ F_NAME ] )
         ENDIF
      ENDIF
   NEXT
   IF lDeleteFolder .AND. Len( Directory( cFolder + "\*.*" ) ) == 0
      DirRemove( cFolder )
   ENDIF

   RETURN Nil

FUNCTION HB_GT_SYS()

   REQUEST HB_GT_WVG_DEFAULT

   RETURN Nil

FUNCTION AppVersaoExe()

   RETURN ""

FUNCTION AppUserName()

   RETURN ""

STATIC FUNCTION TestSignedEXE( cFileName )

   LOCAL oSignedCode, lOk := .F.

   BEGIN SEQUENCE WITH __BreakBlock()
      oSignedCode := win_OleCreateObject( "CAPICOM.SignedCode" )
      oSignedCode:FileName := cFileName
      oSignedCode:Verify()
      lOk := .T.
   ENDSEQUENCE
   IF ! lOk
      ShowAlert( "Not installed CAPICOM and/or EXE not signed" )
      IF .F.
         SignEXE( cFileName )
      ENDIF
   ENDIF

   RETURN lOk

STATIC FUNCTION ShowNormal( cText )

   ? cText

   RETURN Nil

STATIC FUNCTION ShowAlert( cText )

   LOCAL cSetColor := SetColor( "N/GR*" )

   ? cText
   SetColor( cSetColor )
   stErro := .T.
   Inkey(2)

   RETURN Nil

FUNCTION ShellExecuteOpen( cFileName, cParameters, cPath, nShow )

   wapi_ShellExecute( Nil, "open", cFileName, cParameters, cPath, hb_DefaultValue( nShow, 1 ) )

   RETURN Nil

PROCEDURE HB_GTSYS

   REQUEST HB_GT_WVG_DEFAULT

   RETURN

   /*
   ar x lib.a
   objcopy --redefine-sym MsgYesNo=FWMsgYesNo nome.o
   ar rcs lib.a *.o

   #-ldflags=-Wl,--allow-multiple-definition -s -static
   ####SET HB_USER_LDFLAGS=-Wl,--allow-multiple-definition -s -static
   */

FUNCTION Reorganize( hSetup )

   LOCAL dDatIni, dDatFim, dItem, nMax := -1, nQtd := 0, xName, xValue

   dDatIni := Date() - Day( Date() ) + 1
   dDatFim := Last_Day( dDatIni )
   FOR dItem = dDatIni TO dDatFim
      IF hb_HHasKey( hSetup, Dtos( dItem ) )
         xValue := hSetup[ Dtos( dItem ) ]
         nMax   := Max( nMax, xValue )
         nQtd   += 1
      ENDIF
   NEXT
   IF nQtd != 0
      xName := hb_Dtoc( Date(), "YYYYMM" ) + " Max"
      IF ! hb_HHasKey( hSetup, xName )
         hb_HSet( hSetup, xName, nMax )
      ELSE
         hSetup[ xName ] := nMax
      ENDIF
   ENDIF

   RETURN Nil

FUNCTION Last_Day( dData )

   dData += ( 40 - Day( dData ) )
   dData -= Day( dData )

   RETURN dData

STATIC FUNCTION SignEXE( cFileName )

   LOCAL oSignedCode, oSigner, lOk := .F.

   BEGIN SEQUENCE WITH __BreakBlock()
      oSignedCode := win_OleCreateObject( "CAPICOM.SignedCode" )
      oSignedCode:FileName := cFileName
      oSigner := win_OleCreateObject( "CAPICOM.Signer" )
      oSigner:Certificate := CAPICOMCertificado( "JPA Tecnologia Ltda SN" )
      oSignedCode:Sign( oSigner )
      oSignedCode:TimeStamp( "http://timestamp.digicert.com" )
      lOk := .T.
   ENDSEQUENCE
   IF ! lOk
      ShowAlert( "Not installed CAPICOM and/or EXE not signed" )
   ENDIF

   RETURN lOk
Tem também um detalhe de resource embutido.
#pragma begin dump
Quando altera o arquivo externo, o fonte não é recompilado, então coloquei no build pra apagar o OBJ.
Também cria um log pra curiosidade/estatística

Código: Selecionar todos

{
  "LastPath": "d:\\fontes\\integra\\",
  "LastBuildDate": "20250216",
  "Day": 51,
  "Year": 2034,
  "Month": 753,
  "Total": 10962,
  "2024": 8928,
  "202409": 1307,
  "202409 Max": 230,
  "202410": 1249,
  "202410 Max": 111,
  "202411": 1257,
  "202411 Max": 141,
  "202412": 824,
  "202412 Max": 106,
  "2025": 2034,
  "2025 Max": 0,
  "202501": 1281,
  "202501 Max": 187,
  "202502": 753,
  "202502 Max": 127,
  "20250201": 17,
  "20250203": 97,
  "20250204": 35,
  "20250205": 127,
  "20250206": 52,
  "20250207": 36,
  "20250209": 47,
  "20250210": 8,
  "20250211": 46,
  "20250212": 38,
  "20250213": 111,
  "20250214": 88,
  "20250216": 51
}
Difícil imaginar tanta compilação assim, só mesmo com contador registrando.

Outra coisa que o build.prg cria é o build.ch

Código: Selecionar todos

#define JOSEQUINTAS_VERSAO    "2025.02.16.1944"
#define JOSEQUINTAS_VERSAO_RC  2502,16,19,44
Com isso, o aplicativo tem número de versão exclusivo pra cada compilação, usando data/hora.

Tem também o debug do harbour forçado, pra não entrar da hwgui, minigui ou fivewin.
Renomeei o arquivo original, é a única forma de acrescentar sem reclamação.
Testo no build.prg também, inclusive se é a versão correta, se o conteúdo bate com o debug original.

Tudo coisa relativamente simples, apenas fui acrescentando pra reduzir o trabalho braçal, ou pra não esquecer de fazer, como o debug.

Configuração de compilação

Enviado: 17 Fev 2025 15:59
por JoséQuintas
O que entra no lugar do upx, mas fazendo uso do upx:

Código: Selecionar todos

FUNCTION Main(...)

   LOCAL aParams, Item, cFile := ""

   aParams := hb_AParams()
   FOR EACH Item IN aParams
      IF ".exe" $ Lower( Item )
         cFile := Lower( Item )
         EXIT
      ENDIF
   NEXT
   IF ! Empty(  cFile )
      RUN ( "UPX_EXE.EXE --lzma " + cFile )
   ENDIF

   RETURN Nil
o harbour chama o UPX, este entra no lugar e altera o parâmetro pra -lzma.
Não procurei se dá pra fazer de outra forma.
O upx original vira UPX_EXE.EXE

Difícil lembrar todos esses detalhes que uso, se formatar a máquina.
Mas o build.exe lembra.

Então... o c.bat vai ficar no path e chamar o build no lugar dele.
o build.exe vai alterar ESSE bat, deixo sempre no mesmo lugar.

Configuração de compilação

Enviado: 17 Fev 2025 17:15
por developer
Obrigado por compartilhar, interessante ver como opera, achei prático e garante que o processo mantem-se homogêneo.

Configuração de compilação

Enviado: 18 Fev 2025 10:12
por JoséQuintas
Faltou dizer, pode ser importante pra alguns.

Passei a usar mingw DWARF, pra poder usar FIVEWIN.
À primeira vista, pro harbour tanto faz, não vi diferença entre usar POSIX ou outra.

fivewin usa dwarf, então tem que ser mingw dwarf.

Gero o harbour aqui, compilo as LIBs aqui, fivewin não tem opção, é do jeito que vier.
Já usei mingw 4.6, 7.3, 14.2, atualmente com 15.0 pré-lançamento.

fivewin vém com harbour, hmg 3 vém com harbour, hmg extended vém com harbour, oohg vém com harbour.
Não uso nenhum deles.
Uso a última versão oficial de harbour.

É melhor qual versão mingw ? é melhor harbour 3.2, 3.4 ou xharbour.
Sei lá... tenho mais o que fazer... só importa que tudo funcione como o esperado.

Mas tem isto: compilador 32 bits pode limitar a memória em 2GB, 3GB ou 4GB.
Uso o mingw que libera mais memória, melhor sobrar do que faltar.

Configuração de compilação

Enviado: 21 Fev 2025 17:53
por JoséQuintas
Mais uma:

E na mistura de LIBs ?

GTWVG tem uma coisa que atrapalha.
No GTWVG.HBC tem a linha headers=wvt.ch,naolembro.ch,maisoutro.ch
Isso faz com que esses arquivos CH sejam acrescentados pra TODOS os fontes.
Mas isso não pode entrar em MINIGUI, HWGUI, FIVEWIN, etc que dá conflito.
É só remover.

A partir daí, se um fonte GTWVG precisa desses CH, é colocar lá #include "gtwvg.ch"
Também criei esse.
Ele contém.... aqueles headers que foram removidos

GTWVG.CH
#include "wvt.ch"
#include "naolembro.ch"
#include "maisoutro.ch"

Troquei o automático problemático por um #include manual que não dá problema.
Assim gtwvg não mexe nos fontes das outras LIBs.

Demorei pra perceber que o problema era esse.
Antes disso compilava separado pra cada LIB.

Configuração de compilação

Enviado: 21 Fev 2025 19:45
por JoséQuintas
Tentei dar uma organizada melhor no fonte.

Código: Selecionar todos

/*
BUILD - PRE-COMPILACAO
José Quintas

2024.11.03 - win_RegRead()/win_RegWrite() parcial
*/

ANNOUNCE HB_GTSYS
REQUEST errorsys

#include "directry.ch"

STATIC lErrorMsg := .F.

FUNCTION Main( ... )

   LOCAL aParamList, aSignList := {}, aCmdList := {}

   SetMode( 33, 100 )
   SetColor( "W/B" )
   Altd()

   Setup_DELETE_TEMP( "c:\temp\" )
   Setup_SET_ENV( @aCmdList )
   Setup_SET_PATH( @aCmdList )
   Setup_CHECK_ON_PATH()
   Setup_IS_SIGNED( @aCmdList )
   Setup_HBMK_HBC( "d:\harbour\bin\" )
   Setup_SET_DEBUG()
   Setup_BUILD_LOG()

   aParamList := hb_aParams()

   Setup_CREATE_BAT( aParamList, aSignList, aCmdList )

   IF lErrorMsg
      Inkey(5)
   ENDIF

   RETURN Nil

STATIC FUNCTION Setup_DELETE_TEMP( cPath )

   LOCAL aFile, cItem
   LOCAL aList := { ;
      "ze_resource.*", ;
      "*.reso", ;
      "_hbmkaut*.*" }

   FOR EACH cItem IN aList
      FOR EACH aFile IN Directory( cPath + cItem )
         fErase( cPath + aFile[ F_NAME ] )
      NEXT
   NEXT

   RETURN Nil

STATIC FUNCTION Setup_SET_ENV( aCmdList )

   LOCAL aItem, cName, cValue
   LOCAL aList := { ;
      { "HB_BUILD_DYN", "no" }, ;
      { "HB_BUILD_CONTRIB_DYN", "no" }, ;
      { "HB_BUILD_STRIP", "all" }, ;
      { "HB_BUILD_SHARED", "no" }, ;
      { "HB_COMPILER", "mingw" }, ;
      { "HB_INSTALL_PREFIX", "d:\harbour" }, ;
      { "HB_LANG", "EN" } }

   FOR EACH aItem IN aList
      cName := aItem[ 1 ]
      cValue := aItem[ 2 ]
      IF Empty( win_RegRead( "HKCU\Environment\" + cName ) ) ;
         .OR. ! win_RegRead( "HKCU\Environment\" + cName ) == cValue ;
         .OR. Empty( GetEnv( cName ) ) ;
         .OR. ! GetEnv( cName ) == cValue
         ShowAlert( "Adding to ENV " + cName + "=" + cValue )
         ShellExecuteOpen( "setx", cName + " " + cValue,, 0 )
         win_RegWrite( "HKCU\Environment\" + cName, cValue )
         AAdd( aCmdList, "SET " + cName + "=" + cValue )
      ENDIF
   NEXT

   RETURN Nil

STATIC FUNCTION Setup_SET_PATH( aCmdList )

   LOCAL cPath, aPathList, lChanged := .F., cItem

   cPath := win_RegRead( "HKCU\Environment\Path" )
   hb_Default( @cPath, "" )

   aPathList := hb_RegExSplit( ";", cPath )
   FOR EACH cPath IN { ;
         "d:\harbour\bin", ;
         "d:\harbour\comp\mingw32\bin", ;
         "d:\tools\util" }
      IF ASCan( aPathList, { | e | Lower( cPath ) $ Lower( e ) } ) == 0
         ShowAlert( "Adding PATH " + cPath )
         AAdd( aPathList, cPath )
         AAdd( aCmdList, "SET PATH=%PATH%;" + cPath )
         lChanged := .T.
      ENDIF
   NEXT
   IF lChanged
      cPath := ""
      FOR EACH cItem IN aPathList
         cPath += cItem + ";"
      NEXT
      win_RegWrite( "HKCU\Environment\Path", cPath )
      // ShellExecuteOpen( "setx", [PATH "] + + cPath + ["] )
   ENDIF

   RETURN Nil

STATIC FUNCTION Setup_CHECK_ON_PATH()

   LOCAL cFile
   LOCAL aList := { ;
      "c.bat", ;
      "assina.bat", ;
      "hbmk2.exe", ;
      "gcc.exe", ;
      "harbour.exe", ;
      "upx.exe" }

   FOR EACH cFile IN aList
      IF Empty( CheckFileOnPath( cFile ) )
         ShowAlert( cFile + " not in PATH" )
      ENDIF
   NEXT

   RETURN Nil

STATIC FUNCTION Setup_IS_SIGNED( aCmdList )

   LOCAL cFile, cPathFile

   FOR EACH cFile IN { "hbmk2.exe", "harbour.exe", "upx.exe" } // "upx.exe", "mingw32-make.exe", "gcc.exe" }
      cPathFile := CheckFileOnPath( cFile )
      IF Empty( cPathFile )
         ShowAlert( cFile + " not in PATH" )
      ELSEIF ! TestSignedEXE( cPathFile + cFile )
         AAdd( aCmdList, "CALL assina " + cPathFile + cFile )
         ShowAlert( cPathFile + cFile + " not signed" )
      ENDIF
   NEXT

   RETURN Nil

STATIC FUNCTION Setup_HBMK_HBC( cPath )

   LOCAL cText, cItem, lUpdate := .F.
   LOCAL aList := { ;
      "mt=yes", ;
      "gui=yes", ;
      "strip=yes", ;
      "fullstatic=yes", ;
      "PRGFLAGS=-m -n -w3 -es2 -ge1 -DMT_EXPERIMENTAL -DHB_NO_GTGUI=YES", ;
      "incpaths=d:/fontes/util/build", ;
      "libpaths=d:/fontes/integra/libjpa", ;
      "libpaths=d:/fontes/integra/boletoclass", ;
      "libpaths=d:/fontes/integra/sefazclass", ;
      "libpaths=d:/github/rmchartclass", ;
      "libpaths=d:/github/wvgtest", ;
      "libpaths=d:/github/hwgui", ;
      "libpaths=d:/github/oohg", ;
      "libpaths=d:/github/hmge", ;
      "libpaths=d:/github/hmg3", ;
      "libpaths=d:/github/fivewin" }

   IF ! File( cPath + "hbmk2.exe" )
      ShowAlert( "not found hbmk.exe folder" )
      RETURN Nil
   ENDIF
   IF File( cPath + "hbmk.hbc" )
      cText := MemoRead( cPath + "hbmk.hbc" )
      IF Right( cText, 2 ) != hb_Eol()
         cText += hb_Eol()
      ENDIF
   ELSE
      cText := ""
   ENDIF
   FOR EACH cItem IN aList
      IF ! cItem $ cText
         cText += cItem + hb_Eol()
         lUpdate := .T.
         ShowAlert( "Adding to hbmk.hbc " + cItem )
      ENDIF
   NEXT
   IF lUpdate
      hb_MemoWrit( cPath + "hbmk.hbc", cText )
   ENDIF

   RETURN Nil

STATIC FUNCTION Setup_SET_DEBUG()

   LOCAL cLib1 := "", cLib2, cPathLib := "d:\harbour\lib\win\mingw\"

   IF File( cPathLib + "libforcedebug.a" )
      cLib1 := MemoRead( cPathLib + "libforcedebug.a" )
   ENDIF
   cLib2 := MemoRead( cPathLib + "libhbdebug.a" )
   IF ! cLib1 == cLib2
      ShowAlert( "Saving libforcedebug.a" )
      hb_MemoWrit( cPathLib + "libforcedebug.a", cLib2 )
   ENDIF

   RETURN Nil

STATIC FUNCTION Setup_BUILD_LOG()

   LOCAL cDateTime, cTxt, cFileName, hSetup, cLastPath, aItem
   LOCAL aList := { ;
      { "LastPath", "" }, ;
      { "LastBuildDate", "" }, ;
      { "Total", 0 }, ;
      { "Year", 0 }, ;
      { "Month", 0 }, ;
      { "Day", 0 } }

   AAdd( aList, { Left( Dtos( Date() ), 4 ), 0 } )
   AAdd( aList, { Left( Dtos( Date() ), 4 ) + " Max", 0 } )
   AAdd( aList, { Left( Dtos( Date() ), 6 ), 0 } )
   AAdd( aList, { Left( Dtos( Date() ), 6 ) + " Max", 0 } )
   AAdd( aList, { Dtos( Date() ), 0 } )

   cFileName := hb_FNameDir( hb_ProgName() ) + hb_FNameName( hb_ProgName() )
   hSetup    := hb_JsonDecode( MemoRead( cFileName + ".json" ) )
   IF ValType( hSetup ) != "H"
      hSetup := hb_Hash()
   ENDIF
   FOR EACH aItem IN aList
      IF ! hb_HHasKey( hSetup, aItem[ 1 ] )
         hb_HSet( hSetup, aItem[ 1 ], aItem[ 2 ] )
      ENDIF
   NEXT

   cDateTime := Dtos( Date() ) + Substr( Time(), 1, 2 ) + Substr( Time(), 4, 2 )
   cLastPath := hSetup[ "LastPath" ]

   IF Day( Date() ) != Day( Stod( hSetup[ "LastBuildDate" ] ) )
      hSetup[ "Day" ] := 0
   ENDIF
   IF Month( Date() ) != Month( Stod( hSetup[ "LastBuildDate" ] ) )
      hSetup[ "Month" ] := 0
   ENDIF
   IF Year( Date() ) != Year( Stod( hSetup[ "LastBuildDate" ] ) )
      hSetup[ "Year" ] := 0
   ENDIF
   hSetup[ "Total" ] += 1
   hSetup[ "Year" ]  += 1
   hSetup[ "Month" ] += 1
   hSetup[ "Day" ]   += 1
   hSetup[ "LastPath" ]   := hb_cwd()
   hSetup[ "LastBuildDate" ] := Dtos( Date() )
   hSetup[ Left( Dtos( Date() ), 4 ) ] += 1
   hSetup[ Left( Dtos( Date() ), 6 ) ] += 1
   hSetup[ Dtos( Date() ) ] += 1

   Reorganize( @hSetup )

   hb_MemoWrit( cFileName + ".json", hb_JsonEncode( hSetup, .T. ) )

   IF ! Upper( cLastPath )  == Upper( hb_cwd() )
      DeleteContent( "c:\temp", .F. )
   ENDIF

   cTxt := "#define JOSEQUINTAS_VERSAO    " + ["]  + Transform( cDateTime, "@R 9999.99.99.9999" ) + ["] + hb_Eol()
   cTxt += "#define JOSEQUINTAS_VERSAO_RC  " + Transform( Substr( cDateTime, 3 ), "@R 9999,99,99,99" ) + hb_Eol()
   hb_MemoWrit( cFileName + ".ch", cTxt )
   IF File( "build.ch" ) // save on folder too, IF have it
      hb_MemoWrit( "build.ch", cTxt )
   ENDIF
   AEval( Directory( "*.upx" ), { | e | fErase( e[ F_NAME ] ) } ) // temporary upx

   RETURN Nil

STATIC FUNCTION Setup_CREATE_BAT( aParamList, aSignList, aCmdList )

   LOCAL oElement, cPath, cCmdDefault := "", cCmd := "", aHbpList := {}, aList, cItem
   LOCAL cBatFile := "d:\tools\util\c.bat", cFile, aFile, cHbp, lMultiHbp := .F.

   cCmd := hb_ProgName() + " %*" + hb_Eol()
   FOR EACH cItem IN aCmdList
      cCmd += cItem + hb_Eol()
   NEXT

   cPath := Upper( hb_cwd() )
   IF ! Empty( aSignList )
      FOR EACH cFile IN aSignList
         cCmd += "call assina " + cFile + hb_Eol()
      NEXT
   ENDIF

   IF Len( aParamList ) != 0 .AND. aParamList[ 1 ] == "/cmd"
      hb_ADel( aParamList, 1, .T. )
   ELSE
      IF hb_AScan( aParamList, { | e | e $ "|-w0|-w1|-w2|-w3|"  } ) == 0
         AAdd( aParamList, "-w3" )
      ENDIF
      IF hb_AScan( aParamList, { | e | e $ "|-es0|-es1|-es2|" } ) == 0
         AAdd( aParamList, "-es2" )
      ENDIF
      IF hb_AScan( aParamList, { | e | e == "-m" } ) == 0
         AAdd( aParamList, "-m" )
      ENDIF
      IF hb_ASCan( aParamList, { | e | e == "-n" } ) == 0
         AAdd( aParamList, "-n" )
      ENDIF
      //IF ASCan( aParamList, "-gc3" ) == 0
      //   AAdd( aParamList, "-gc3" )
      //ENDIF
      IF Len( Directory( "*.hbp" ) ) != 0
         aList := Directory( "*.hbp" )
         FOR EACH aFile IN aList
            IF Lower( aFile[ F_NAME ] ) != "hwguidyn.hbp" // error IF create it
               AAdd( aHbpList, aFile[ F_NAME ] )
            ENDIF
         NEXT
      ELSEIF Len( Directory( "*.prg" ) ) != 0
         AAdd( aParamList, "*.prg" )
         AAdd( aParamList, "*.rc" )
      ELSE
         ShowNormal( hb_cwd() )
      ENDIF
   ENDIF
   AAdd( aParamList, "-strip" )
   AAdd( aParamList, "-compr" )
   AAdd( aParamList, "-workdir=c:\temp" )
   AAdd( aParamList, "-q" )
   AAdd( aParamList, "-I" + hb_FNameDir( hb_ProgName() ) )
   IF "SAMPLE" $ Upper( hb_cwd() )
      IF "HMGE" $ Upper( hb_cwd() )
         AAdd( aParamList, "hmge.hbc" )
      ENDIF
      IF "HWGUI" $ Upper( hb_cwd() )
         AAdd( aParamList, "hwgui.hbc" )
      ENDIF
      IF "OOHG" $ Upper( hb_cwd() )
         AAdd( aParamList, "oohg.hbc" )
      ENDIF
      IF "FIVEWIN" $ Upper( hb_cwd() )
         AAdd( aParamList, "fivewin.hbc" )
      ENDIF
   ENDIF
   FOR EACH oElement IN aParamList
      cCmdDefault += oElement + " "
   NEXT
   IF Len( aHbpList ) == 0
      cCmd += "HBMK2 " + cCmdDefault + hb_Eol()
   ELSE
      IF Len( aHbpList ) > 1
         lMultiHbp := .T.
      ENDIF
      FOR EACH cHbp IN aHbpList
         IF lMultiHbp
            //cCmd += "ECHO S | DEL C:\TEMP\*.*" + hb_Eol()
         ENDIF
         IF "-hbcontainer" $ MemoRead( cHbp ) .AND. ! "-rebuildall" $ cCmdDefault
            cCmdDefault += " -rebuildall"
         ENDIF
         cCmd += "HBMK2 " + cHbp + " " + cCmdDefault + hb_Eol()
      NEXT
   ENDIF
   DO CASE
   CASE "\SJPA\"     $ cPath; cCmd += "if exist ..\sjpa.exe call assina.bat ..\sjpa.exe" + hb_Eol()
   CASE "\HAROLDO\"  $ cPath; cCmd += "if exist hl.exe      call assina.bat hl.exe"      + hb_Eol()
   CASE "\INTEGRA\"  $ cPath; cCmd += "if exist jpa.exe     call assina.bat jpa.exe"     + hb_Eol()
   CASE "\BUILD\"    $ cPath; cCmd += "if exist build.exe call assina.bat build.exe"   + hb_Eol()
   CASE "\UTIL\UPX\" $ cPath
      cCmd += "if exist pupx.exe  call assina.bat pupx.exe" + hb_Eol()
      cCmd += "if exist pupx.exe copy pupx.exe \tools\util\upx.exe" + hb_Eol()
   ENDCASE
   IF ! hb_DirExists( "c:\temp" )
      hb_DirCreate( "c:\temp" )
      ShowAlert( "Created c:\temp" )
   ENDIF
   hb_MemoWrit( cBatFile, cCmd )

   RETURN Nil

STATIC FUNCTION ShowNormal( cText )

   ? cText

   RETURN Nil

STATIC FUNCTION ShowAlert( cText )

   LOCAL cSetColor := SetColor( "N/GR*" )

   ? cText
   SetColor( cSetColor )
   lErrorMsg := .T.
   Inkey(2)

   RETURN Nil

STATIC FUNCTION TestSignedEXE( cFileName )

   LOCAL oSignedCode, lOk := .F.

   BEGIN SEQUENCE WITH __BreakBlock()
      oSignedCode := win_OleCreateObject( "CAPICOM.SignedCode" )
      oSignedCode:FileName := cFileName
      oSignedCode:Verify()
      lOk := .T.
   ENDSEQUENCE
   IF ! lOk
      ShowAlert( "Not installed CAPICOM and/or EXE not signed" )
      IF .F.
         SignEXE( cFileName )
      ENDIF
   ENDIF

   RETURN lOk

FUNCTION ShellExecuteOpen( cFileName, cParameters, cPath, nShow )

   wapi_ShellExecute( Nil, "open", cFileName, cParameters, cPath, hb_DefaultValue( nShow, 1 ) )

   RETURN Nil

FUNCTION Reorganize( hSetup )

   LOCAL dDatIni, dDatFim, dItem, nMax := -1, nQtd := 0, xName, xValue

   dDatIni := Date() - Day( Date() ) + 1
   dDatFim := Last_Day( dDatIni )
   FOR dItem = dDatIni TO dDatFim
      IF hb_HHasKey( hSetup, Dtos( dItem ) )
         xValue := hSetup[ Dtos( dItem ) ]
         nMax   := Max( nMax, xValue )
         nQtd   += 1
      ENDIF
   NEXT
   IF nQtd != 0
      xName := hb_Dtoc( Date(), "YYYYMM" ) + " Max"
      IF ! hb_HHasKey( hSetup, xName )
         hb_HSet( hSetup, xName, nMax )
      ELSE
         hSetup[ xName ] := nMax
      ENDIF
   ENDIF

   RETURN Nil

FUNCTION Last_Day( dData )

   dData += ( 40 - Day( dData ) )
   dData -= Day( dData )

   RETURN dData

STATIC FUNCTION SignEXE( cFileName )

   LOCAL oSignedCode, oSigner, lOk := .F.

   BEGIN SEQUENCE WITH __BreakBlock()
      oSignedCode := win_OleCreateObject( "CAPICOM.SignedCode" )
      oSignedCode:FileName := cFileName
      oSigner := win_OleCreateObject( "CAPICOM.Signer" )
      oSigner:Certificate := CAPICOMCertificado( "JPA Tecnologia Ltda SN" )
      oSignedCode:Sign( oSigner )
      oSignedCode:TimeStamp( "http://timestamp.digicert.com" )
      lOk := .T.
   ENDSEQUENCE
   IF ! lOk
      ShowAlert( "Not installed CAPICOM and/or EXE not signed" )
   ENDIF

   RETURN lOk

STATIC FUNCTION DeleteContent( cFolder, lDeleteFolder )

   LOCAL oFiles, oFile, lDelete

   hb_Default( @lDeleteFolder, .F. )

   ShowNormal( "Delete on  " + cFolder )
   oFiles := Directory( cFolder + "\*.*", "D" )
   FOR EACH oFile IN oFiles
      IF "D" $ oFile[ F_ATTR ]
         IF oFile[ F_NAME ] != "." .AND. oFile[ F_NAME ] != ".."
            DeleteContent( cFolder + "\" + oFile[ F_NAME ], .T. )
         ENDIF
      ELSE
         lDelete := .T.
         DO CASE
         CASE hb_FNameExt( oFile[ F_NAME ] ) == ".c"
         CASE hb_FNameExt( oFile[ F_NAME ] ) == ".o"
         CASE ASCan( { ".PRG", ".DBF", ".CH", ".HBP", ".RC" }, { | e | e == Upper( hb_FNameExt( oFile[ F_NAME ] ) ) } ) != 0
            lDelete := .F.
         CASE oFile[ F_DATE ] != Date()
         CASE Left( oFile[ F_TIME ], 4 ) != Left( Time(), 4 )
         OTHERWISE
            lDelete := .F.
         ENDCASE
         IF lDelete
            ShowNormal( "Deleting " + cFolder + "\" + oFile[ F_NAME ] )
            fErase( cFolder + "\" + oFile[ F_NAME ] )
         ENDIF
      ENDIF
   NEXT
   IF lDeleteFolder .AND. Len( Directory( cFolder + "\*.*" ) ) == 0
      DirRemove( cFolder )
   ENDIF

   RETURN Nil

STATIC FUNCTION CheckFileOnPath( cFile )

   LOCAL cPath, cPathFile

   cFile := Lower( cFile )
   FOR EACH cPath IN hb_RegExSplit( ";", GetEnv( "PATH" ) )
      IF Right( cPath, 1 ) != "\"
         cPath := cPath + "\"
      ENDIF
      IF File( cPath + cFile )
         cPathFile := cPath
         EXIT
      ENDIF
   NEXT

   RETURN cPathFile

FUNCTION AppVersaoExe()

   RETURN ""

FUNCTION AppUserName()

   RETURN ""

PROCEDURE HB_GTSYS

   REQUEST HB_GT_WVG_DEFAULT

   RETURN

Configuração de compilação

Enviado: 21 Fev 2025 20:18
por JoséQuintas
Pra quem quiser fazer ajuste:

1) Defina onde vai ficar seu C.BAT, será o ponto de partida
Setup_SET_PATH() - coloque checagem do path aqui
Setup_CREATE_BAT() - coloque o nome/path aqui

2) Defina onde vai ficar seu harbour.exe e compilador C
Setup_SET_PATH() - coloque checagem do path aqui
Setup_CHECK_ON_PATH() - ajuste se usar outro compilador C

3) Defina se quer defaults para o harbour
Setup_HBMK_HBC() - coloque defaults aqui

4) Defina se quer checar assinatura de harbour.exe, hbmk2.exe e outros
Setup_IS_SIGNED() - coloque o teste aqui

5) Debug alternativo, acho que só eu
Setup_SET_DEBUG()
O hbmk2 não permite adicionar LIB do próprio harbour.
Pra anular o debug do fivewin, preciso colocar o debug do harbour primeiro.
Minha saída: faço uma cópia com outro nome, outro nome o hbmk2 deixa.
Aqui testa o conteúdo, porque se eu recompilar o harbour, o build lembra de atualizar a cópia.
O build não mexe com o debug, o HBP do aplicativo é que adiciona a cópia.

6) Confirme os adicionais
Setup_CREATE_BAT()
Aqui tem sobre adicionar parâmetros, assinar conforme nome, etc.

O C.BAT vai conter igual Setup_CREATE_BAT()
Tem as linhas padrão, adicione só mais uma. o BAT vai ser regravado sempre.
É o BAT que chama o build e depois prossegue com o que for gravado nele.

Essas coisas o hbmk2 não faz, mas não sei como criar addon pra ele, isso é possível.

Configuração de compilação

Enviado: 21 Fev 2025 20:39
por JoséQuintas
Um exemplo interessante: MODIFICO O FIVEWIN
Isso não tem nada a ver com o restante, então é resolvido no próprio fivewin.

tem lá o changed.prg, compilado gera a lib changed.a
no FIVEWIN.HBC, que contém "o assunto fivewin", coloco essa lib antes das libs do fivewin.

Não preciso mexer no build, não preciso mexer no projeto, ao adicionar fivewin ele entra alterado.
E usando as LIBs totalmente originais !!!!!!

Lembram?
FIVEWIN.HBC é pra indicar PATH de include, PATH de lib, NOMES DE LIB, etc. que serão usadas no fivewin.
O nome tá lá, pronto, resolvido.
Pra que complicar ?

Uma compilação fora do comum se torna uma compilação comum.
Posso até adicionar aquele debug forçado nesse hbc.