Page 2 of 4

Re: Lib - PB 6.20

Posted: Sun Dec 15, 2024 12:13 pm
by pf shadoko
i think fred will add a keyword
I suggested “Public”, but why not “External”?

constants are rarely isolated, most of them are (or should be) in an enumeration block
you can therefore put “external” before an enumeration block

Re: Lib - PB 6.20

Posted: Sun Dec 15, 2024 1:07 pm
by ChrisR
I think that having one or more Externals-EndExternals (or Resident-EndResident) blocks is probably the most flexible, allowing you to add whatever you want, constants, enumerations, structures, macros... between the 2 tags.
And so, no need to search for every keyword: Structure-EndStructure, Enumeration-EndEnumeration,...

To rebuild the resident and avoid the message: Structure already declared: xxx (in a resident file), it must be removed first or saved.
Also, I think it would be better to compile the resident first and if compiled successfully, compile the library with the lines between Externals, EndExternals removed in tmp.pb, to avoid the same message, already declared.

Re: Lib - PB 6.20

Posted: Sun Dec 15, 2024 1:10 pm
by le_magn
I have a question, in the past the creation of personal libraries was done via tailbite or other systems, but the end result was always the same, that is, after a few years these libraries no longer worked on the new versions of purebasic, see the problem symbol case, all Gnozal libraries with time became obsolete and incompatible, my question is, this new feature integrated to purebasic how will it prevent the same thing from happening? Because otherwise I can't see the benefits, personally I am terrified to use libraries created by third parties given the very bad experience I had in the past with the ones from Gnozal...

Re: Lib - PB 6.20

Posted: Sun Dec 15, 2024 6:53 pm
by idle
I see no problem if the source is available but I would be reluctant to use a 3rd party lib without it.

Re: Lib - PB 6.20

Posted: Sun Dec 15, 2024 7:02 pm
by idle
External is a bit more familiar.
And using blocks beginresidents endresidents would make a lot more sense

Re: Lib - PB 6.20

Posted: Mon Dec 16, 2024 3:08 am
by ChrisR
idle wrote: Sun Dec 15, 2024 6:53 pm I see no problem if the source is available but I would be reluctant to use a 3rd party lib without it.
I fully agree :)

I've made a few changes so that the resident and library files can be rebuilt without error: xxx already declared: yyy (in a resident file)
And using case-sensitive blocks Residents-EndResidents

Code: Select all

;Residents
#Hello = 10

Structure Name
  String.s
  Value.i
EndStructure
;.....
;EndResidents

Code: Select all

EnableExplicit

Structure residents 
  *residents 
  len.i 
EndStructure   

#separateurs=" =:;,()[]{}+-/*.\<>?%|&"+#CR$+#LF$+Chr(34)

Procedure.s lirefic(nom.s,nobom=1)
  Protected txt.s,n,sf
  n=ReadFile(-1,nom)
  sf=ReadStringFormat(n)
  txt=ReadString(n,sf|#PB_File_IgnoreEOL)
  CloseFile(n)   
  ProcedureReturn txt
EndProcedure

Procedure ecrirefic(nom.s,txt.s,format=#PB_UTF8)
  Protected n
  If FileSize(nom)>=0:DeleteFile(nom):EndIf
  n=OpenFile(-1,nom,format):WriteString(n,txt,format):CloseFile(n)   
EndProcedure

Procedure.s Stringparse(t.s,before.s,after.s,pi=0)
  Protected pf
  pi=FindString(t,before,pi+1)
  If pi=0:ProcedureReturn:EndIf 
  pf=FindString(t,after,pi):If pf=0:pf=Len(t):EndIf
  pi+Len(before)
  ProcedureReturn Mid(t,pi,pf-pi)
EndProcedure

Procedure FindStringRev(t.s,find.s,p=0,mode=#PB_String_CaseSensitive)
  Protected l=Len(find)
  If p=0:p=Len(t):EndIf
  Repeat
    If p=0 Or Mid(t,p,l)=find:Break:EndIf
    p-1
  ForEver
  ProcedureReturn p
EndProcedure

Procedure.i FindStringww(txt.s,mot.s,p=1,mode=0); findstring whole word
  Repeat
    p=FindString(txt,mot,p,mode):If p=0:Break:EndIf
    If FindString(#separateurs,Mid(txt,p-1,1))>0 And FindString(#separateurs,Mid(txt,p+Len(mot),1))>0:ProcedureReturn p:EndIf
    p+Len(mot)
  ForEver
EndProcedure

Procedure.s ReplaceStringww(txt.s,mot.s,rep.s,p=1,mode=0); ReplaceString whole word
  Protected lm,lr
  
  lm=Len(mot)
  lr=Len(rep)
  Repeat
    p=FindStringww(txt,mot,p+1,mode):If p=0:Break:EndIf
    txt=Left(txt,p-1)+rep+Mid(txt,p+lm)
    p+lm-lr+1
  ForEver
  ProcedureReturn txt
EndProcedure

;####################################################################################################################################################

Procedure.s codefiltre(txt.s) ;-------- crée une version du code contenant des ";"  à la place des commentaires et des """ dans les strings pour faciliter l'analyse du code
  Protected i,n,ch,co,c.w
  
  n=Len(txt)
  Dim t.w(n-1)
  CopyMemory(@ txt,@ t(0),n*2)
  For i=0 To n-1
    c=t(i)
    Select c
      Case 34:ch=~ch
      Case 59:co=1
      Case 13:co=0
    EndSelect      
    If ch:c=34 :EndIf
    If co:c=59:EndIf
    t(i)=c
  Next
  CopyMemory(@ t(0),@ txt,n*2)
  ProcedureReturn txt
EndProcedure

Procedure.s listeparam(List p.s(),txt.s,pi=1) ;-------- met les parametres de proc dans une liste et retourne un string contenant les parametres 
  Protected i,np,ch,pd,pdc,finc,c.s
  ClearList(p())
  
  For i=pi To Len(txt)
    c=Mid(txt,i,1)
    If ch=0
      If c="(":np+1:If np=1:pd=i:pdc=i:EndIf:EndIf
      If c=")":np-1:If np=0:finc=1:EndIf:EndIf
      If c="," And np=1:finc=1:EndIf
      If finc:
        AddElement(p()):p()=Trim(Mid(txt,pdc+1,i-pdc-1)):pdc=i
        If finc And np=0:Break:EndIf
        finc=0
      EndIf
    EndIf
    If c=#DQUOTE$:ch=~ch:EndIf
  Next
  ;ForEach p():Debug p():Next:Debug "---"+Mid(txt,pd+1,i-pd-1):End
  ProcedureReturn Mid(txt,pd+1,i-pd-1)
EndProcedure

Procedure.s paramx(List p.s(), n, nval,declaration) ; <- retourne les parametres sous forme litérales
  Protected i,r.s,v.s
  ForEach p()
    i+1:If i>n:Break:EndIf
    v=StringField(p(),Bool(i>nval)+1,"=")
    If declaration=0 And FindString(v,"("):v=Stringparse(v," ","(")+"()":EndIf
    r+","+v
  Next
  ProcedureReturn Mid(r,2)
EndProcedure

Procedure.s parametres_optionels(fic.s,*Residents.residents) ;-------- gestion des parametres optionnels du fichier fic (il y a tjrs la possibilité de les gérer nous même (si on met les versions numerotées)
  CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_Windows :#lgsep=#CRLF$
    CompilerCase #PB_OS_Linux   :#lgsep=#LF$
    CompilerCase #PB_OS_MacOS   :#lgsep=#CR$
  CompilerEndSelect
  
  Protected i,p,pp,pi,pl,pf,num,npo,npf,ok,rl,lr
  Protected.s param,paramo,nom,nomnum,proccode,proccodei,remplace,nums,ret,deb,QuickHelp,ts
  NewList l.s() ; liste parametre
  NewList ll.s(); liste parametre
  
  pf=1
  Repeat
    ;========================================== recup Residents
    pi=FindString(fic,";Residents",pf):If pi=0:Break:EndIf
    pf=FindString(fic,";EndResidents",pi+10)+13:If pf=13:Break: EndIf   
    ts=Mid(fic,pi,pf-pi)
    fic=ReplaceString(fic,ts,"") ; the extracted code must be deleted in fic to avoid the error: xxx already declared: xxx (in a resident file)
    pf=pi
    ts=Mid(ts,11,Len(ts)-10-13)  ; extracted code without both flags
    lr=rl 
    rl+PokeS(*Residents\residents+rl,ts,Len(ts))
    *residents\len=rl
  ForEver
  
  pf=1
  Repeat     
    ;========================================== recup de la ProcedureDLL
    pi=FindString(fic,"ProcedureDLL",pf):If pi=0:Break:EndIf
    pf=FindString(fic,"EndProcedure",pi)+12:If pf=12:Break:EndIf
    proccode=Mid(fic,pi,pf-pi)
    proccodei=proccode
    
    pl=FindString(proccode,#lgsep)
    nom=Trim(Stringparse(proccode," ","("))
    ok=1:For i=1 To Len(nom):If FindString(#separateurs,Mid(nom,i,1)):ok=0:EndIf:Next:If ok=0 Or nom="":Continue:EndIf
    num=Val(Right(nom,1))
    param=listeparam(l(),proccode)
    
    ;========================================== QuickHelp 
    QuickHelp=" QuickHelp "+nom+"("+param+") - "
    p=FindStringRev(fic,#lgsep,pi-3)+Len(#lgsep)
    If Mid(fic,p,1)=";":p=p+1:Else:p=pi:QuickHelp=";"+QuickHelp+#lgsep:EndIf
    fic =Left(fic ,p-1)+QuickHelp+Mid(fic ,p)
    pi+Len(QuickHelp)
    pf+Len(QuickHelp)
    
    If num:Continue:EndIf; on abandonne si n° à la 1er occurence
    
    ;========================================== suppression de ses valeurs par defaut
    paramo=param
    While FindString(paramo,"="):paramo=ReplaceString(paramo,"="+Stringparse(paramo+",","=",","),""):Wend
    proccode=ReplaceString(proccode,param,paramo)
    
    npo=CountString(param,"="); !!!
    If npo=0:Continue:EndIf   ; on abandonne si nombre de param optionel=0
    
    ;========================================== creation des versions numérotées 
    npf=ListSize(l())-npo
    
    deb=Left(proccode,FindString(proccode,"(")-1)
    nomnum=nom+Str(npo+1)
    remplace=ReplaceString(proccode,nom,nomnum,0 ,1,1)
    If FindString(proccode,"ProcedureReturn")>0:ret="ProcedureReturn ":Else:ret="":EndIf
    For i=npo To 1 Step -1
      If i>1:nums=Str(i):Else:nums="":EndIf
      remplace+#lgsep+deb+nums+"("+paramx(l(),npf+i-1,100,1)+")"+#lgsep+ret+nomnum+"("+paramx(l(),npf+npo,npf+i-1,0)+")"+#lgsep+"EndProcedure"
    Next
    
    fic =Left(fic ,pi-1)+remplace+Mid(fic ,pf)
    pf+Len(remplace)-Len(proccodei)
    
    ;========================================== remplacement des appels de la ProcedureDLL (et DeclareDLL) par leur version numérotée
    p=0
    Repeat
      p=FindStringww(fic,nom,p+1,#PB_String_NoCase):If p=0:Break:EndIf
      pp=FindStringRev(fic,#lgsep,p)+Len(#lgsep)
      If Mid(fic,pp,12)="ProcedureDLL" Or Mid(fic,pp,1)=";" Or Mid(fic,p+Len(nom),1)<>"(":Continue:EndIf  ; !!!     
      
      paramo=listeparam(ll(),fic,p)
      If Bool(Mid(fic,pp,10)="DeclareDLL")
        param=paramx(l(),npf+npo,100,1)
      Else
        paramx(l(),npf+npo,npf,0)
        param=paramo       
        For i=ListSize(ll()) To ListSize(l()) -1
          SelectElement(l(),i)
          param+","+Mid(l(),FindString(l(),"=")+1)
        Next
      EndIf
      
      nums=Str(npo+1)
      fic=ReplaceString(fic,nom,nom+nums,#PB_String_NoCase,p,1)
      fic=ReplaceString(fic,paramo,param,#PB_String_NoCase,p,1)
      If p<pf:pf+Len(nums)+Len(param)-Len(paramo):EndIf
    ForEver
  
ForEver

ProcedureReturn fic
EndProcedure

;- Main
Define.s code,rescode,fic,chd,chs,s,libname,Flag,msg,pg.i
Global residents.residents 

chs=ProgramParameter(0)
If FileSize(chs) 
  residents\residents=AllocateMemory(FileSize(chs))
EndIf 

fic=GetFilePart(chs)
code=parametres_optionels(lirefic(chs),@residents)

If residents\len > 0  ;-------- write resident and compile
  chd=GetTemporaryDirectory()+"tmp.res"
  libname=Left(fic,FindString(fic,".")-1)+".res" 
  rescode = PeekS(residents\residents,residents\len>>1) 
  Debug libname+#CRLF$+"==>"+#CRLF$+rescode+#CRLF$+"----------"
  
  ecrirefic(chd,rescode)
  
  pg=RunProgram(#PB_Compiler_Home+"Compilers\pbcompiler",chd+" /IGNORERESIDENT "+libname+" /RESIDENT "+#PB_Compiler_Home+"\residents\"+libname,"", #PB_Program_Open|#PB_Program_Read)
  While ProgramRunning(pg):If AvailableProgramOutput(pg):s+ReadProgramString(pg)+#CRLF$:EndIf:Wend:CloseProgram(pg)
  If s > ""
    MessageRequester("Create Resident Error:","Resident Source File: %Temp%\tmp.res"+#CRLF$+#CRLF$+s)
    End 1
  Else
    msg="Your Resident has been Created as "+#DQUOTE$+libname+#DQUOTE$+#CRLF$+#CRLF$
  EndIf
EndIf 

;-------- write library and compile
chd=GetTemporaryDirectory()+"tmp.pb"
libname=Left(fic,FindString(fic,".")-1)

ecrirefic(chd,code)
Debug libname+#CRLF$+"==>"+#CRLF$+code+#CRLF$+"----------"

pg = FindString(code,"; IDE Options = PureBasic",2)   ;Get compiler options, If Save Settings is to the end of the source file
If pg
  code=Mid(code,pg);+50
  If FindString(code,"EnableThread",2) :Flag+" /THREAD"       :EndIf
  If FindString(code,"EnableOnError",2):Flag+" /LINENUMBERING":EndIf
  If FindString(code,"DPIAware",2)     :Flag+" /DPIAWARE"     :EndIf
  If FindString(code,"EnableXP",2)     :Flag+" /XP"           :EndIf
  If FindString(code,"EnableAdmin",2)  :Flag+" /ADMINISTRATOR":EndIf
  If FindString(code,"EnableUser",2)   :Flag+" /USER"         :EndIf
  If FindString(code,"DllProtection",2):Flag+" /DLLPROTECTION":EndIf
  If FindString(code,"SharedUCRT",2)   :Flag+" /UCRT"         :EndIf
EndIf
Flag+" /OPTIMIZER /PURELIBRARY /OUTPUT "
Debug "Flag: "+Flag

pg=RunProgram(#PB_Compiler_Home+"Compilers\pbcompilerc",chd+Flag+libname,"", #PB_Program_Open|#PB_Program_Read)
While ProgramRunning(pg):If AvailableProgramOutput(pg):s+ReadProgramString(pg)+#CRLF$:EndIf:Wend:CloseProgram(pg)
If s>""
  MessageRequester("Create Lib Error:","Library Source File: %Temp%\tmp.pb"+#CRLF$+#CRLF$+s)
  End 1
Else
  If msg
    msg+"Your Library has been Created as "+#DQUOTE$+libname+#DQUOTE$+#CRLF$+#CRLF$+"Restart your Compiler to use them"
  Else
    msg+"Your Library has been Created as "+#DQUOTE$+libname+#DQUOTE$+#CRLF$+#CRLF$+"Restart your Compiler to use it"
  EndIf
  MessageRequester("Create Lib",msg)
EndIf

Re: Lib - PB 6.20

Posted: Mon Dec 16, 2024 3:24 am
by idle
Much easier thanks

Re: Lib - PB 6.20

Posted: Mon Dec 16, 2024 12:55 pm
by pf shadoko
in relation to structure and constant/enumeration :
I could automatically determine what is used by “procedureDLL”.

I don't know if you can do the same with prototypes and interfaces (I don't know them, I don't use them)

Re: Lib - PB 6.20

Posted: Mon Dec 16, 2024 3:03 pm
by Fred
You can use the /IGNORERESIDENT flag to ignore the load of a resident (instead of deleting it)

Re: Lib - PB 6.20

Posted: Mon Dec 16, 2024 3:57 pm
by ChrisR
Fred wrote: Mon Dec 16, 2024 3:03 pm You can use the /IGNORERESIDENT flag to ignore the load of a resident (instead of deleting it)
Oh yes, thanks :)
I've updated the above code with also the compiler options for the Library, If Save Settings is to the end of the Library source file.
Exept IncludeFile, this nice tool must be pretty complete now I guess.

Re: Lib - PB 6.20

Posted: Mon Dec 16, 2024 4:52 pm
by pf shadoko
Fred should add a keyword (external), or see if we can do without it (see my previous post).

moreover, resident management must be done in a separate pass. here, as it is, procedureDLL must be positioned after “external”.
for includes, I think it's simple (a recursive function that incurs includes)

I'll make a v2 with your modifications shortly

Re: Lib - PB 6.20

Posted: Mon Dec 16, 2024 5:25 pm
by ChrisR
pf shadoko wrote: Mon Dec 16, 2024 4:52 pm moreover, resident management must be done in a separate pass. here, as it is, procedureDLL must be positioned after “external”.
for includes, I think it's simple (a recursive function that incurs includes)
Yes indeed, add pf=1 at the end of pi=FindString(fic,";Residents",pf) : If pi : ..... : pf=1 : Else
should do it, but a second loop with position would be better.
While waiting for your v2, I updated on the post above

#
pf shadoko wrote: Mon Dec 16, 2024 4:52 pm Fred should add a keyword (external), or see if we can do without it (see my previous post).
Yes, I'd seen it and it would be a good thing.
Maybe you can anticipate it so you don't have to update it for the next beta, with something like:

Code: Select all

#HandleExternal=#True
CompilerIf #HandleExternal
  pi=FindString(fic,";Residents",pf)
Well, that was just my 2 cents, I'll just leave you to prepare v2 :)

#
pf shadoko wrote: Thu Dec 12, 2024 7:01 pm je trouve plus explicite comme ça: là, on connait les valeurs par défaut
Oui, finalement je suis d'accord, c'est plus explicite en effet avec les valeurs par défaut

Re: Lib - PB 6.20

Posted: Mon Dec 16, 2024 7:37 pm
by dcr3
Although this is a great tool, this should be taken into consideration.

List, Array and Map parameters can cause issues when exported with ProcedureDLL.

Otherwise the tool will hang.

Re: Lib - PB 6.20

Posted: Mon Dec 16, 2024 8:06 pm
by pf shadoko
no, these limitations no longer apply
Have you tested it?

Re: Lib - PB 6.20

Posted: Mon Dec 16, 2024 9:39 pm
by morosh
Trying your tool right now (creating Createlib.exe then testing it with your example), I got:
Error: Linker
Error at line 50: Can't create the library file:
c:\Program Files\PureBasic\purelibrairies/userlibrairies/Ext2D
with both \ and /
what it could be?
edit:
Trying also Fred example in a command line window, I got:
E:\my_data\prog\pb\TEST>"C:\Program Files\PureBasic\Compilers\pbcompilerc" test.pb --purelibrary --output test
PureBasic 6.20 Beta 1 - C Backend (Windows - x64)
Compiling test.pb
Loading external libraries...
Starting compilation...
69 lines processed.
Creating threaded version of the PureLibrary...
Starting compilation...
69 lines processed.
Error: Linker
Error at line 65: Can't create the library file:
C:\Program Files\PureBasic\purelibraries/userlibraries/Test
thanks