Page 1 of 1

How to Compile Universal Binaries!!

Posted: Mon Mar 09, 2009 12:54 pm
by lexvictory
As many of you know, this is not possibly natively in PB, so I created a tool that does it!
It can run as a IDE Tool (you need to manually put in the full path to the unix exe), or you can put it in the dock and drag your pb files to it.
It reads the compiler options from the end of the source file, then gets you to confirm and then hit compile. Simple!

Unfortunately, I don't think it will work with IDE defined constants (compile count and the like) - but I haven't tested this!
Only works with .app bundles. (non bundles are easy enough to do in terminal)

Requirements: Intel Mac (Intel PB won't run on a PPC Mac ;))
Source and binary available: http://demonioardente.us.to/pb/PBUniversalCompile.dmg
If you compile it yourself you will have to copy the Info.plist into the .app bundle after compilation if you wish to drag source files to the dock icon.

Make sure you copy the bundle somewhere where your user account can write to; it writes a .prefs file inside it's bundle

Let me know if you have any improvements/bugs!
(All icons used are copyright their respective owners)

Re: How to Compile Universal Binaries!!

Posted: Tue Mar 10, 2009 10:13 pm
by jamirokwai
lexvictory wrote:As many of you know, this is not possibly natively in PB, so I created a tool that does it!
Wow. Cute!
I can't test it though on ppc because I only own a MacBook, but you may have saved me a lot of time.
If there is anybody out there using a ppc-machine, please test my tool from
http://www.quadworks.de/download.php?ar ... nhance.zip

If it works, I would recommend your little tool to everyone coding on Mac OS X, lexvictory!!!
Thank you very much!

Posted: Wed Mar 11, 2009 7:03 am
by lexvictory
:D
Yes, definitely someone test it - I don't have a PPC machine to test on either

Posted: Wed Mar 11, 2009 12:17 pm
by lexvictory
ok, just tested with arch -ppc in terminal, and it seems to start rosetta (hard drive noise and long startup time) and does execute the PPC code
(my test program while developing this was a one liner with a messagerequester showing #PB_Compiler_Processor)

Re: How to Compile Universal Binaries!!

Posted: Thu Mar 12, 2009 12:07 am
by jamirokwai
jamirokwai wrote:
lexvictory wrote:As many of you know, this is not possibly natively in PB, so I created a tool that does it!
Wow. Cute!
I can't test it though on ppc because I only own a MacBook, but you may have saved me a lot of time.
If there is anybody out there using a ppc-machine, please test my tool from
http://www.quadworks.de/download.php?ar ... nhance.zip

If it works, I would recommend your little tool to everyone coding on Mac OS X, lexvictory!!!
Thank you very much!
Hm. A friend of mine owns a G5 iMac. My little tool from above does not run on this machine.
Either this is not working because of errors in my code, or there are other issues...

Posted: Thu Mar 12, 2009 3:01 am
by lexvictory
try it with a simple thing - like a messagerequester that shows a different message based on what processor it is running on.
only then can you isolate if it is a programming error, or this tool's fault.

Re: How to Compile Universal Binaries!!

Posted: Mon Jan 06, 2014 6:57 pm
by DoubleDutch
Can you post the source to this tool, the download links are no longer working.

Re: How to Compile Universal Binaries!!

Posted: Tue Jan 07, 2014 4:52 am
by J. Baker
DoubleDutch wrote:Can you post the source to this tool, the download links are no longer working.
Give App Chef a try...
http://www.forums.purebasic.com/english ... 27&t=57491

Re: How to Compile Universal Binaries!!

Posted: Tue Jan 07, 2014 10:23 am
by DoubleDutch
Thanks, but I want to do create the universal binary of the two OSX files on Windows once they have been injected with some data, that's why I needed the source. I also wanted to know if I could add my own common data segment into the combined executable that they could both share.

Re: How to Compile Universal Binaries!!

Posted: Tue Jan 07, 2014 2:41 pm
by lexvictory
I can't find the file at the moment - I used a separate folder for the mac stuff.

From what I remember though it basically just compiled the program (once in Intel, once in PPC), then used a command line program (that should be in Xcode stuff) to combine it into the one .app bundle/folder. You can possibly find the name of the command on the forum here, or definitely on google.

I don't believe there's a way to do it on windows however.

As for a common data segment you'd likely be best to put it inside the Resources folder in the bundle; I'm not sure that it combines them into one physical binary file (I think there's still 2 binaries inside the bundle), but it's been a while and I don't know how that works with datasections.

I'll still try find that program, but it won't tell you much more than that.

EDIT: aaaand just as I post that i found the folder!

Re: How to Compile Universal Binaries!!

Posted: Tue Jan 07, 2014 2:44 pm
by lexvictory

Code: Select all

;written thanks to http://developer.apple.com/technotes/tn2005/tn2137.html
;thanks to freak @ http://purebasic.fr/english/viewtopic.php?t=34231 for the drag to dock icon functinality.

#eventNotHandledErr = -9874

#CoreEventClass = 'aevt'
#AEOpenDocuments = 'odoc'
 
#typeFSS = 'fss '
#typeAEList = 'list'
#typeFSRef = 'fsrf'
#keyDirectObject = '----'

#typeNull = 'null'
#noErr = 0

Structure FSRef
  hidden.b[80]
EndStructure

Structure AEDesc
  desctiptorType.l
  dataHandle.l
EndStructure 

Declare OpenTheWindow(pbsrc.s)

ProcedureCDLL OpenDocument(*appleEvt, *reply, refcon)
 
  ; extract the event parameters
  If AECreateDesc_(#typeNull, 0, 0, @documents.AEDesc) = #noErr
    If AEGetParamDesc_(*appleEvt, #keyDirectObject, #typeAEList, @documents)  = #noErr
      If AECountItems_(@documents, @n) = 0

        *Buffer = AllocateMemory(1000)
        If *Buffer

          ; There can be multiple files sent
          For i = 1 To n
            If AEGetNthPtr_(@documents, i, #typeFSRef, @keyWd, @typeCd, @fileRef.FSRef, SizeOf(FSRef), @actualSize) = #noErr
              If FSRefMakePath_(@fileRef, *Buffer, 1000) = #noErr

                File$ = PeekS(*Buffer, -1, #PB_Ascii)
                If FileSize(File$) >= 0 And FindString(LCase(File$), ".pb", 1)
                  OpenTheWindow(File$)
                EndIf
               
              EndIf
            EndIf
          Next i
       
          FreeMemory(*Buffer)
        EndIf
       
      EndIf
    EndIf
    AEDisposeDesc_(@documents)
  EndIf
 
EndProcedure

Procedure.s BundleFilename()
  Protected exe.s = ProgramFilename()
  Protected contentsindex = FindString(exe, "/Contents/MacOS",1)
  ProcedureReturn Left(exe, contentsindex)
EndProcedure

Global PB_Intel_Path.s , PB_PPC_Path.s



Procedure Error(error.s)
  MessageRequester("Error", error)
EndProcedure

Procedure WaitUntilWindowIsClosed()
  Repeat
  Until WaitWindowEvent()= #PB_Event_CloseWindow
  ProcedureReturn 1
EndProcedure

;compileroptions:
Global useunicode, usethread, useonerror, subsystem.s, lastexe.s, icon.s, useinlineasm
Enumeration;gadgets
#pbsrc
#onerror
#icon
#iconbrowse
#lastexe
#subsystem
#unicodemode
#threadmode
#useinlineasm
#compile
#log
EndEnumeration

Procedure DisableGadgets(state)
  DisableGadget(#pbsrc,state)
  DisableGadget(#onerror,state)
  DisableGadget(#icon,state)
  DisableGadget(#iconbrowse,state)
  DisableGadget(#lastexe,state)
  DisableGadget(#subsystem,state)
  DisableGadget(#unicodemode,state)
  DisableGadget(#threadmode,state)
  DisableGadget(#useinlineasm,state)
  DisableGadget(#compile,state)
EndProcedure


Procedure OpenTheWindow(pbsrc.s)
If ReadFile(0, pbsrc)
  While Eof(0)=0
    line.s = ReadString(0)
    If FindString(line, "; IDE Options =",1)
      inoptionssection = 1
    ElseIf inoptionssection
      key.s = StringField(line, 2, " ")
      ;Debug "key: "+key
      Select Trim(key)
        Case "EnableOnError"
          useonerror = 1
        Case "UseIcon"
          valindex = FindString(line, "=", 1)+2
          icon = Mid(line, valindex)
        Case "Executable"
          valindex = FindString(line, "=", 1)+2
          lastexe = Mid(line, valindex)
        Case "EnableUnicode"
          useunicode = 1
        Case "EnableThread"
          usethread = 1
        Case "EnableAsm"
          useinlineasm = 1
        Case "SubSystem"
          valindex = FindString(line, "=", 1)+2
          subsystem = Mid(line, valindex)
      EndSelect
      ;valindex = FindString(line, "=", 1)+2
      ;val.s = Mid(line, valindex)
      ;Debug val
    EndIf
  Wend
EndIf



If lastexe = "" : lastexe=Left(pbsrc, Len(pbsrc)-3)+".app" : EndIf

OpenWindow(0, 0,0, 600, 700,"Confirm Compiler Options - PB Universal Binary Creator", #PB_Window_ScreenCentered|#PB_Window_SystemMenu )
TextGadget(#PB_Any, 1,3,70,20,"PB Source:"): StringGadget(#pbsrc, 72, 1, 525, 20, pbsrc)
TextGadget(#PB_Any, 1, 28, 70, 20,"Output to:") : StringGadget(#lastexe, 72, 26, 525, 20, lastexe)
TextGadget(#PB_Any, 1, 54,30, 20, "Icon:") : StringGadget(#icon, 32, 52, 498, 20, icon) : ButtonGadget(#iconbrowse, 535, 52, 60, 20, "...")
TextGadget(#PB_Any, 1, 80, 70, 20, "Subsystem:") : StringGadget(#subsystem, 72, 78, 525, 20, subsystem)
CheckBoxGadget(#onerror, 1, 100, 400, 20, "Enable OnError Lines support")
SetGadgetState(#onerror, useonerror)
CheckBoxGadget(#unicodemode, 1, 125, 400, 20, "Compile in Unicode mode")
SetGadgetState(#unicodemode, useunicode)
CheckBoxGadget(#threadmode, 1, 150, 400, 20, "Compile in ThreadSafe mode")
SetGadgetState(#threadmode, usethread)
CheckBoxGadget(#useinlineasm, 1, 175, 400,20, "Enable Inline ASM support")
SetGadgetState(#useinlineasm, useinlineasm)
ButtonGadget(#compile, 250, 200, 100, 20, "Compile!")
ListViewGadget(#log, 1,230, 598, 468)
AddGadgetItem(#log, -1, "["+FormatDate("%hh:%ii:%ss", Date())+"] Loaded source code: "+pbsrc)

EndProcedure

If OpenPreferences(BundleFilename()+"Contents/Resources/pblocs.prefs")
  PB_Intel_Path.s = ReadPreferenceString("pb_intel", "")
  PB_PPC_Path.s = ReadPreferenceString("pb_ppc", "")
EndIf

writeout = 0

If PB_Intel_Path = ""
  MessageRequester("Select PB Intel Folder", "I need to know where you PB Intel (x86) folder is, please input it into the requester that follows")
  PB_Intel_Path = PathRequester("Select PB Intel (x86) folder.", "/Applications/PureBasic/")
  If PB_Intel_Path = ""
    MessageRequester("Error", "No PB Intel path was supplied, exiting")
    End
  EndIf
  writeout = 1
EndIf
If PB_PPC_Path = ""
  MessageRequester("Select PB PPC Folder", "I need to know where you PB PPC (PowerPC) folder is, please input it into the requester that follows")
  PB_PPC_Path = PathRequester("Select PB PowerPC (PPC) folder.", "/Applications/PureBasicPPC/")
  If PB_PPC_Path = ""
    MessageRequester("Error", "No PB PPC path was supplied, exiting")
    End
  EndIf
  writeout = 1
EndIf

If writeout
  If FileSize(BundleFilename()+"Contents/Resources") = -1
    CreateDirectory(BundleFilename()+"Contents/Resources")
  EndIf
  If CreatePreferences(BundleFilename()+"Contents/Resources/pblocs.prefs")
    WritePreferenceString("pb_intel", PB_Intel_Path)
    WritePreferenceString("pb_ppc", PB_PPC_Path)
    ClosePreferences()
  Else
    MessageRequester("Warning", "Could not save PB locations, you will be prompted again on next start")
  EndIf
EndIf

If #PB_Compiler_Debugger = 0
  SetCurrentDirectory(BundleFilename())
EndIf
  
Global currdir.s = GetCurrentDirectory()
If FileSize(ProgramParameter(0)) > 0 And FindString(LCase(ProgramParameter(0)), ".pb", 1)
  pbsrc.s = ProgramParameter(0)
  OpenTheWindow(pbsrc)
EndIf

OpenWindow(123, 0,0,0,0,"Universal PB Compiler", #PB_Window_Invisible)
If AEInstallEventHandler_(#CoreEventClass, #AEOpenDocuments, @OpenDocument(), 0, 0) <> #NoErr
  MessageRequester("Warning", "Could not register handler for dragging")
EndIf 

Repeat
  event = WaitWindowEvent()
  Select event
    Case #PB_Event_CloseWindow
      ;quit = 1
      CloseWindow(0)
    Case #PB_Event_Menu
      If EventMenu() = #PB_Menu_Quit
        ;Debug "quit pushed!"
        quit = 1
      EndIf
    Case #PB_Event_Gadget
      If EventGadget() = #iconbrowse
        newicon.s = OpenFileRequester("Select .icns file", currdir, "*.icns", 0)
        If newicon
          SetGadgetText(#icon, newicon)
        EndIf
      ElseIf EventGadget() = #compile
        DisableGadgets(1)
        AddGadgetItem(#log, -1, "["+FormatDate("%hh:%ii:%ss", Date())+"] Start Universal compile")
        SetCurrentDirectory(GetPathPart(GetGadgetText(#pbsrc)))
        currdir = GetCurrentDirectory()
        compileroptions.s = ""
        If GetGadgetText(#icon) <> "" : compileroptions= "-n "+#DQUOTE$+GetGadgetText(#icon)+#DQUOTE$ : EndIf
        If GetGadgetText(#subsystem)<> "" : compileroptions + " -s "+#DQUOTE$+GetGadgetText(#subsystem)+#DQUOTE$ : EndIf
        If GetGadgetState(#onerror) : compileroptions + " -l" : EndIf
        If GetGadgetState(#unicodemode) : compileroptions + " -u" : EndIf
        If GetGadgetState(#threadmode) : compileroptions + " -t" : EndIf
        If GetGadgetState(#useinlineasm) : compileroptions + " -i" : EndIf
        lastexe = GetGadgetText(#lastexe)
        ;compileroptions + " -e "+#DQUOTE$+GetGadgetText(#lastexe)+#DQUOTE$+" "+#DQUOTE$+GetGadgetText(#pbsrc)+#DQUOTE$
        ;AddGadgetItem(#log, -1, compileroptions)
        AddGadgetItem(#log, -1, "["+FormatDate("%hh:%ii:%ss", Date())+"] Compiling Intel mode")
        SetEnvironmentVariable("PUREBASIC_HOME", PB_Intel_Path);in case we're not running as a PB tool.
        compiler = RunProgram(PB_Intel_Path+"compilers/pbcompiler", compileroptions+ " -e "+#DQUOTE$+lastexe+#DQUOTE$+" "+#DQUOTE$+GetGadgetText(#pbsrc)+#DQUOTE$, currdir, #PB_Program_Open|#PB_Program_Read|#PB_Program_Hide)
        If compiler
          While ProgramRunning(compiler)
            If AvailableProgramOutput(compiler)
              ;Debug "output available"
              compileroutput.s = ReadProgramString(compiler)
              If FindString(LCase(compileroutput), "error",0)
                wasanerror = 1
                Error(compileroutput)
              ElseIf compileroutput = "- Feel the ..PuRe.. Power -"
                Break;out of the while loop
              EndIf
              AddGadgetItem(#log,-1, "["+FormatDate("%hh:%ii:%ss", Date())+"] "+compileroutput)
            Else
              While WindowEvent()
              Wend
              Delay(20)
            EndIf
          Wend
          CloseProgram(compiler)
          ;-PPC compile
          AddGadgetItem(#log, -1, "["+FormatDate("%hh:%ii:%ss", Date())+"] Compiling PPC mode")
          SetEnvironmentVariable("PUREBASIC_HOME", PB_PPC_Path)
          compiler = RunProgram(PB_PPC_Path+"compilers/pbcompiler", compileroptions+ " -e "+#DQUOTE$+ReplaceString(lastexe, ".app", "-ppc.app", #PB_String_NoCase)+#DQUOTE$+" "+#DQUOTE$+GetGadgetText(#pbsrc)+#DQUOTE$, currdir, #PB_Program_Open|#PB_Program_Read|#PB_Program_Hide)
          If compiler
            While ProgramRunning(compiler)
              If AvailableProgramOutput(compiler)
                ;Debug "output available"
                compileroutput.s = ReadProgramString(compiler)
                If FindString(LCase(compileroutput), "error",0)
                  wasanerror = 1
                  Error(compileroutput)
                ElseIf compileroutput = "- Feel the ..PuRe.. Power -"
                  Break;out of the while loop
                EndIf
                AddGadgetItem(#log,-1, "["+FormatDate("%hh:%ii:%ss", Date())+"] "+compileroutput)
              Else
                While WindowEvent()
                Wend
                Delay(20)
              EndIf
            Wend
            CloseProgram(compiler)
            baseappexe.s = lastexe+"/Contents/MacOS/"+RemoveString(GetFilePart(lastexe), ".app", #PB_String_NoCase)
            ppcappexe.s = ReplaceString(lastexe, ".app", "-ppc.app", #PB_String_NoCase)+"/Contents/MacOS/"+RemoveString(GetFilePart(lastexe), ".app", #PB_String_NoCase)+"-ppc"
            RenameFile(baseappexe, baseappexe+"-intel")
            RunProgram("lipo", "-create "+#DQUOTE$+baseappexe+"-intel"+#DQUOTE$+" "+#DQUOTE$+ppcappexe+#DQUOTE$+" -output "+#DQUOTE$+baseappexe+#DQUOTE$, currdir, #PB_Program_Wait)
            If FileSize(baseappexe) < 0;lipo failure
              error("Merging binaries with lipo failed")
              AddGadgetItem(#log,-1, "["+FormatDate("%hh:%ii:%ss", Date())+"] Universal compile Failed!")
              DisableGadgets(0)
              Continue
            EndIf
            DeleteFile(lastexe+"/Contents/MacOS/"+RemoveString(GetFilePart(lastexe), ".app", #PB_String_NoCase)+"-intel")
            DeleteDirectory(ReplaceString(lastexe, ".app", "-ppc.app"), "", #PB_FileSystem_Recursive|#PB_FileSystem_Force)
          Else
            error("Could not run PPC pbcompiler")
            DisableGadgets(0)
            Continue
          EndIf
        Else
          error("Could not run Intel pbcompiler")
          DisableGadgets(0)
          Continue
        EndIf
        AddGadgetItem(#log,-1, "["+FormatDate("%hh:%ii:%ss", Date())+"] Universal compile done")
        DisableGadgets(0)
      EndIf
  EndSelect
Until quit = 1

Re: How to Compile Universal Binaries!!

Posted: Tue Jan 07, 2014 2:48 pm
by lexvictory
apple appear to have changed their site so that apple link doesnt work. try http://web.archive.org/web/200901111958 ... n2137.html

It seems they do get put into the one file, but it appears to just be a container format.

Re: How to Compile Universal Binaries!!

Posted: Tue Jan 07, 2014 3:31 pm
by DoubleDutch
Thanks, I'll take a looka nd see what is generated. :)