PureLibrary Creator - PB 6.20
- pf shadoko
- Enthusiast
- Posts: 385
- Joined: Thu Jul 09, 2015 9:07 am
Re: Lib - PB 6.20
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
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
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.
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
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
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
External is a bit more familiar.
And using blocks beginresidents endresidents would make a lot more sense
And using blocks beginresidents endresidents would make a lot more sense
Re: Lib - PB 6.20
I fully agreeidle 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'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
Last edited by ChrisR on Mon Dec 16, 2024 6:47 pm, edited 6 times in total.
Re: Lib - PB 6.20
Much easier thanks
- pf shadoko
- Enthusiast
- Posts: 385
- Joined: Thu Jul 09, 2015 9:07 am
Re: Lib - PB 6.20
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)
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
You can use the /IGNORERESIDENT flag to ignore the load of a resident (instead of deleting it)
Re: Lib - PB 6.20
Oh yes, thanksFred 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)

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.
- pf shadoko
- Enthusiast
- Posts: 385
- Joined: Thu Jul 09, 2015 9:07 am
Re: Lib - PB 6.20
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
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
Yes indeed, add pf=1 at the end of pi=FindString(fic,";Residents",pf) : If pi : ..... : pf=1 : Elsepf 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)
should do it, but a second loop with position would be better.
While waiting for your v2, I updated on the post above
#
Yes, I'd seen it and it would be a good thing.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).
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)

#
Oui, finalement je suis d'accord, c'est plus explicite en effet avec les valeurs par défautpf shadoko wrote: Thu Dec 12, 2024 7:01 pm je trouve plus explicite comme ça: là, on connait les valeurs par défaut
Re: Lib - PB 6.20
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.
List, Array and Map parameters can cause issues when exported with ProcedureDLL.
Otherwise the tool will hang.
- pf shadoko
- Enthusiast
- Posts: 385
- Joined: Thu Jul 09, 2015 9:07 am
Re: Lib - PB 6.20
no, these limitations no longer apply
Have you tested it?
Have you tested it?
Re: Lib - PB 6.20
Trying your tool right now (creating Createlib.exe then testing it with your example), I got:
what it could be?
edit:
Trying also Fred example in a command line window, I got:
with both \ and /Error: Linker
Error at line 50: Can't create the library file:
c:\Program Files\PureBasic\purelibrairies/userlibrairies/Ext2D
what it could be?
edit:
Trying also Fred example in a command line window, I got:
thanksE:\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
PureBasic: Surprisingly simple, diabolically powerful