cg@2596: "{ Package: 'stx:libtool2' }" cg@2596: cg@2596: Object subclass:#ProjectBuilder cg@2596: instanceVariableNames:'package projectDefinitionClass sourceCodeManager buildDirectory cg@2598: myWorkingDirectory mySTXTopDirectory myTopDirectory' cg@2596: classVariableNames:'PreviousBuildDirectory' cg@2596: poolDictionaries:'' cg@2596: category:'System-Support-Projects' cg@2596: ! cg@2596: cg@2596: cg@2596: !ProjectBuilder class methodsFor:'examples'! cg@2596: cg@2596: example1 cg@2596: Smalltalk loadPackage:'stx:projects/helloWorldApp' asAutoloaded:true. cg@2596: cg@2596: self new cg@2596: package:'stx:projects/helloWorldApp'; cg@2596: build cg@2596: ! ! cg@2596: cg@2596: !ProjectBuilder methodsFor:'accessing'! cg@2596: cg@2596: package:aPackageIDOrSymbol cg@2596: package := aPackageIDOrSymbol asPackageId. cg@2596: ! cg@2596: cg@2596: projectDefinitionClass:something cg@2596: projectDefinitionClass := something. cg@2596: ! ! cg@2596: cg@2596: !ProjectBuilder methodsFor:'building'! cg@2596: cg@2596: build cg@2596: "/ intermediate - this will move into a commonly used utility class cg@2596: "/ (where all the project code support will be collected). cg@2596: cg@2596: |module directory| cg@2596: cg@2596: projectDefinitionClass := ProjectDefinition definitionClassForPackage:package. cg@2596: projectDefinitionClass isNil ifTrue:[ cg@2596: self error:('Missing ProjectDefinition class for "',package asString,'"') cg@2596: ]. cg@2596: cg@2596: "/ ensure that everything is loaded... cg@2596: projectDefinitionClass loadAsAutoloaded:false. cg@2596: projectDefinitionClass loadExtensions. cg@2596: projectDefinitionClass loadAllClassesAsAutoloaded:false. cg@2596: cg@2596: module := package module. cg@2596: directory := package directory. cg@2596: cg@2596: buildDirectory := PreviousBuildDirectory ifNil:[ UserPreferences current buildDirectory ]. cg@2596: buildDirectory isNil ifTrue:[ cg@2596: buildDirectory := Filename tempDirectory construct:'stx_build'. cg@2596: ]. cg@2596: buildDirectory := buildDirectory asFilename. cg@2596: cg@2596: "/ self validateBuildDirectoryIsPresent. cg@2596: cg@2596: PreviousBuildDirectory := buildDirectory. cg@2596: cg@2596: "/ UserPreferences current localBuild:true cg@2596: UserPreferences current localBuild ifFalse:[ cg@2596: SourceCodeManager notNil ifTrue:[ cg@2596: sourceCodeManager := SourceCodeManagerUtilities sourceCodeManagerFor:projectDefinitionClass. cg@2596: ] cg@2596: ]. cg@2596: sourceCodeManager := nil. cg@2596: cg@2598: myTopDirectory := cg@2596: Smalltalk packagePath cg@2596: detect:[:aPath | cg@2596: (aPath asFilename / 'stx' / 'include') exists cg@2596: and: [ (aPath asFilename / 'stx' / 'rules') exists ]] cg@2596: ifNone:nil. cg@2598: myTopDirectory isNil ifTrue:[ cg@2598: self error:('Cannot figure out my top directory (where stx/include and stx/rules are)') cg@2596: ]. cg@2598: myTopDirectory := myTopDirectory asFilename. cg@2598: mySTXTopDirectory := myTopDirectory / 'stx'. cg@2596: cg@2596: self setupBuildDirectory. cg@2599: self halt. cg@2599: self copySTCDirectoryForBuild. cg@2596: self generateSourceFiles. cg@2599: self generateDLLsForLinkage. cg@2598: self halt. cg@2596: cg@2596: OperatingSystem cg@2599: executeCommand:(ParserFlags makeCommand,' exe') cg@2596: inputFrom:nil cg@2596: outputTo:Transcript cg@2596: errorTo:Transcript cg@2599: inDirectory:(buildDirectory / module / directory) cg@2596: onError:[:status| self error:'make failed']. cg@2596: cg@2596: "Created: / 09-08-2006 / 18:37:19 / fm" cg@2596: "Modified: / 09-08-2006 / 19:55:50 / fm" cg@2596: "Modified: / 22-09-2006 / 17:37:11 / cg" cg@2596: ! cg@2596: cg@2596: copyDirectory:relativepath cg@2596: "/ need rules in stx cg@2596: ((Smalltalk projectDirectoryForPackage:'stx') asFilename construct:relativepath) cg@2596: recursiveCopyTo:(buildDirectory construct:'stx'). cg@2596: ! cg@2596: cg@2596: copyDirectoryForBuild:subdir cg@2598: |targetDir targetFile| cg@2596: cg@2596: targetDir := buildDirectory / 'stx' / subdir. cg@2596: targetDir exists ifFalse:[ cg@2596: targetDir makeDirectory. cg@2598: ]. cg@2598: (mySTXTopDirectory / subdir) directoryContentsAsFilenamesDo:[:eachFile | cg@2598: eachFile isDirectory ifFalse:[ cg@2598: targetFile := targetDir / eachFile baseName. cg@2598: (targetFile exists not cg@2598: or:[ targetFile modificationTime < eachFile modificationTime ]) ifTrue:[ cg@2598: self activityNotification:'copying ',eachFile pathName,'...'. cg@2596: eachFile copyTo:(targetDir construct:eachFile baseName) cg@2596: ] cg@2596: ]. cg@2596: ]. cg@2598: self activityNotification:nil cg@2598: ! cg@2598: cg@2599: copySTCDirectoryForBuild cg@2599: |targetDir stc files| cg@2599: cg@2599: targetDir := buildDirectory / 'stx' / 'stc'. cg@2599: targetDir exists ifFalse:[ targetDir makeDirectory ]. cg@2599: cg@2599: stc := OperatingSystem isMSWINDOWSlike cg@2599: ifTrue:[ 'stc.exe' ] cg@2599: ifFalse:[ 'stc' ]. cg@2599: cg@2599: files := #( ) copyWith:stc. cg@2599: cg@2599: files do:[:eachFile | cg@2599: |sourceFile targetFile| cg@2599: cg@2599: sourceFile := mySTXTopDirectory / 'stc' / eachFile. cg@2599: targetFile := targetDir / eachFile. cg@2599: (targetFile exists not cg@2599: or:[ targetFile modificationTime < sourceFile modificationTime ]) ifTrue:[ cg@2599: self activityNotification:'copying ',sourceFile pathName,'...'. cg@2599: sourceFile copyTo:targetFile cg@2599: ]. cg@2599: ]. cg@2599: self activityNotification:nil cg@2599: ! cg@2599: cg@2598: createHeaderFileFor:aClass in:packageTargetDir cg@2598: |instVarList classInstVarList classVarList bindings superclassFilename cg@2598: template file newContents oldContents| cg@2598: cg@2598: instVarList := StringCollection new. cg@2598: aClass instVarNames do:[:v | cg@2598: instVarList add:('OBJ %1;' bindWith:v) cg@2598: ]. cg@2598: classInstVarList := StringCollection new. cg@2598: aClass class instVarNames do:[:v | cg@2598: (v includes:$_) ifTrue:[self halt]. cg@2598: classInstVarList add:('OBJ %1;' bindWith:v) cg@2598: ]. cg@2598: classVarList := StringCollection new. cg@2598: aClass classVarNames do:[:v | cg@2598: classVarList add:('extern OBJ %1_%2;' bindWith:aClass name with:v) cg@2598: ]. cg@2598: cg@2598: bindings := Dictionary new. cg@2598: bindings at:'ClassName' put:aClass name. cg@2598: aClass superclass isNil ifTrue:[ cg@2598: bindings at:'SuperclassName' put:'-'. cg@2598: bindings at:'SuperclassFileInclude' put:nil. cg@2598: ] ifFalse:[ cg@2598: bindings at:'SuperclassName' put:aClass superclass name. cg@2598: bindings at:'SuperclassFileName' put:(superclassFilename := Smalltalk fileNameForClass:aClass superclass). cg@2598: bindings at:'SuperclassFileInclude' put:('#include "%1.STH"' bindWith:superclassFilename). cg@2598: ]. cg@2598: bindings at:'InstVarList' put:instVarList asString. cg@2598: bindings at:'ClassVarList' put:classVarList asString. cg@2598: bindings at:'ClassInstVarList' put:classInstVarList asString. cg@2598: cg@2598: template := cg@2598: '/* This file was generated by ProjectBuilder. */ cg@2598: /* !!!!!!!! Do not change by hand !!!!!!!! */ cg@2598: cg@2598: /* Class: %(ClassName) */ cg@2598: /* Superclass: %(SuperclassName) */ cg@2598: cg@2598: %(SuperclassFileInclude) cg@2598: cg@2598: /* INDIRECTGLOBALS */ cg@2598: #ifdef _HEADER_INST_ cg@2598: %(InstVarList) cg@2598: #endif /* _HEADER_INST_ */ cg@2598: cg@2598: #ifdef _HEADER_CLASS_ cg@2598: %(ClassVarList) cg@2598: #endif /* _HEADER_CLASS_ */ cg@2598: cg@2598: #ifdef _HEADER_CLASSINST_ cg@2598: %(ClassInstVarList) cg@2598: #endif /* _HEADER_CLASSINST_ */ cg@2598: '. cg@2598: newContents := template bindWithArguments:bindings. cg@2598: file := packageTargetDir asFilename / ((Smalltalk fileNameForClass:aClass),'.STH'). cg@2598: (file exists not cg@2598: or:[ (oldContents := file contents) ~= newContents ]) ifTrue:[ cg@2598: file contents: newContents. cg@2598: ]. cg@2596: ! cg@2596: cg@2599: generateDLLsForLinkage cg@2599: |targetBuildDir| cg@2599: cg@2599: targetBuildDir := buildDirectory / package module / package directory. cg@2599: cg@2599: "/ generate header files... cg@2599: (projectDefinitionClass allPreRequisites) cg@2599: do:[:eachPackageToFileout | cg@2599: |packageId packageDef packageModule packageDirectory packageTargetDir cg@2599: dllSource dllSourceDir libraryName dllRelativePath| cg@2599: cg@2599: packageId := eachPackageToFileout asPackageId. cg@2599: packageModule := packageId module. cg@2599: packageDirectory := packageId directory. cg@2599: packageTargetDir := (buildDirectory / packageModule / packageDirectory) recursiveMakeDirectory. cg@2599: cg@2599: packageDef := packageId projectDefinitionClass. cg@2599: libraryName := packageDef libraryName. cg@2599: cg@2599: "/ mhmh - take them from my tree or from the projects/smalltalk execution directory ?? cg@2599: dllSourceDir := myTopDirectory / packageModule / packageDirectory. cg@2599: OperatingSystem isMSWINDOWSlike ifTrue:[ cg@2599: "/ dllRelativePath := 'objvc','/',(libraryName,'.dll'). cg@2599: "/ (dllSourceDir / dllRelativePath) exists cg@2599: false ifFalse:[ cg@2599: dllRelativePath := 'objbc','/',(libraryName,'.dll'). cg@2599: ] cg@2599: ] ifFalse:[ cg@2599: dllRelativePath := libraryName,'.so'. cg@2599: ]. cg@2599: ((dllSourceDir / dllRelativePath) exists cg@2599: and:[ (dllSourceDir / dllRelativePath) fileSize = (packageTargetDir / dllRelativePath) fileSize cg@2599: and:[ (dllSourceDir / dllRelativePath) modificationTime < (packageTargetDir / dllRelativePath) modificationTime cg@2599: "/ and:[ (dllSourceDir / dllRelativePath) sameContentsAs:(packageTargetDir / dllRelativePath) ] cg@2599: ]]) ifFalse:[ cg@2599: (packageTargetDir / dllRelativePath) directory recursiveMakeDirectory. cg@2599: (dllSourceDir / dllRelativePath) copyTo:(packageTargetDir / dllRelativePath). cg@2599: ] cg@2599: ]. cg@2599: ! cg@2599: cg@2596: generateSourceFiles cg@2596: sourceCodeManager notNil ifTrue:[ cg@2596: "/ check out / generate files there cg@2596: self generateSourceFilesByCheckingOutUsing:sourceCodeManager cg@2596: ] ifFalse:[ cg@2596: "/ local build cg@2596: "/ fileout the project cg@2596: self generateSourceFilesByFilingOut cg@2596: ] cg@2596: ! cg@2596: cg@2596: generateSourceFilesByCheckingOutUsing:aSourceCodeManager cg@2596: "/ will no longer be needed/supported cg@2596: cg@2596: |repository stxRepository module directory| cg@2596: cg@2596: self halt. cg@2596: "/ check out / generate files there cg@2596: repository := (aSourceCodeManager repositoryNameForModule:module) ifNil:[aSourceCodeManager repositoryName]. cg@2596: stxRepository := aSourceCodeManager repositoryName. cg@2596: cg@2596: (buildDirectory construct:'stx') exists ifFalse:[ cg@2596: (module ~= 'stx') ifTrue:[ cg@2596: OperatingSystem cg@2596: executeCommand:('cvs -d ',stxRepository,' co stx') cg@2596: inputFrom:nil cg@2596: outputTo:Transcript cg@2596: errorTo:Transcript cg@2596: inDirectory:buildDirectory cg@2596: onError:[:status| self error:'cvs update stx failed']. cg@2596: ]. cg@2596: ]. cg@2596: cg@2596: ((buildDirectory construct:module) construct:'CVS') exists ifFalse:[ cg@2596: OperatingSystem cg@2596: executeCommand:('cvs -d ',repository,' co -l ',directory) cg@2596: inputFrom:nil cg@2596: outputTo:Transcript cg@2596: errorTo:Transcript cg@2596: inDirectory:buildDirectory cg@2596: onError:[:status| self error:'cvs update failed']. cg@2596: ]. cg@2596: OperatingSystem cg@2596: executeCommand:'cvs upd -d' cg@2596: inputFrom:nil cg@2596: outputTo:Transcript cg@2596: errorTo:Transcript cg@2596: inDirectory:(buildDirectory construct:module) cg@2596: onError:[:status| self error:'cvs update failed']. cg@2596: self halt. cg@2596: ! cg@2596: cg@2596: generateSourceFilesByFilingOut cg@2596: "/ local build cg@2596: "/ fileout the project cg@2596: cg@2596: (package module ~= 'stx') ifTrue:[ cg@2596: (buildDirectory / package module) makeDirectory. cg@2596: ]. cg@2596: cg@2599: "/ file out the package(s) which are to be built cg@2598: ((Array with:package)) cg@2596: do:[:eachPackageToFileout | cg@2598: |packageId packageModule packageDirectory packageTargetDir packageDef| cg@2596: cg@2598: packageId := eachPackageToFileout asPackageId. cg@2598: packageModule := packageId module. cg@2598: packageDirectory := packageId directory. cg@2596: packageTargetDir := (buildDirectory / packageModule / packageDirectory) recursiveMakeDirectory. cg@2596: cg@2598: packageDef := packageId projectDefinitionClass. cg@2598: (packageDef compiled_classNames_common , cg@2598: packageDef compiled_classNamesForPlatform) do:[:eachClassName | cg@2598: |cls| cg@2598: cg@2598: cls := Smalltalk classNamed:eachClassName. cg@2598: self assert:cls isLoaded. cg@2598: cls fileOutIn:packageTargetDir cg@2596: ]. cg@2598: cg@2598: "/ (Smalltalk allClassesInPackage:eachPackageToFileout) do:[:cls | cg@2598: "/ cls isPrivate ifFalse:[ cg@2598: "/ cls isLoaded ifFalse:[ cg@2598: "/ self halt. cg@2598: "/ cls autoload. cg@2598: "/ ]. cg@2598: "/ cls fileOutIn:packageTargetDir cg@2598: "/ ] cg@2598: "/ ]. cg@2599: cg@2599: projectDefinitionClass forEachFileNameAndGeneratedContentsDo:[:fileName :fileContents | cg@2599: ((packageTargetDir / fileName) exists cg@2599: and:[ (packageTargetDir / fileName) contents = fileContents ]) ifFalse:[ cg@2599: (packageTargetDir / fileName) contents:fileContents. cg@2599: ]. cg@2599: ]. cg@2599: self halt. cg@2598: ]. cg@2599: cg@2599: "/ generate header files in prerequisite packages... cg@2598: (projectDefinitionClass allPreRequisites) cg@2598: do:[:eachPackageToFileout | cg@2598: |packageId packageDef packageModule packageDirectory packageTargetDir| cg@2598: cg@2598: packageId := eachPackageToFileout asPackageId. cg@2598: packageModule := packageId module. cg@2598: packageDirectory := packageId directory. cg@2598: packageTargetDir := (buildDirectory / packageModule / packageDirectory) recursiveMakeDirectory. cg@2598: cg@2598: packageDef := packageId projectDefinitionClass. cg@2598: (packageDef compiled_classNames_common , cg@2598: packageDef compiled_classNamesForPlatform) do:[:eachClassName | cg@2598: |cls| cg@2598: cg@2598: cls := Smalltalk classNamed:eachClassName. cg@2598: self assert:cls isLoaded. cg@2598: cls isLoaded ifTrue:[ cg@2598: self createHeaderFileFor:cls in:packageTargetDir cg@2598: ]. cg@2598: ]. cg@2596: ]. cg@2596: cg@2596: "/ stx_libbasic2 preRequisitesForBuilding#(#'stx:libbasic') cg@2596: ! cg@2596: cg@2596: setupBuildDirectory cg@2596: buildDirectory exists ifFalse:[ cg@2596: buildDirectory recursiveMakeDirectory. cg@2596: ]. cg@2596: (buildDirectory / 'stx') exists ifFalse:[ cg@2596: (buildDirectory / 'stx') makeDirectory. cg@2596: ]. cg@2596: cg@2596: self copyDirectoryForBuild:'include'. cg@2596: self copyDirectoryForBuild:'rules'. cg@2596: ! cg@2596: cg@2596: validateBuildDirectoryIsPresent cg@2596: cg@2596: ^ self. cg@2596: cg@2596: "/ [ cg@2596: "/ |default directoryIsOKForMe stc | cg@2596: "/ cg@2596: "/ default := (buildDirectory ? cg@2596: "/ PreviousBuildDirectory) cg@2596: "/ ifNil:[ UserPreferences current buildDirectory]. cg@2596: "/ cg@2596: "/ buildDirectory := Dialog requestDirectoryName:'Temporary Work-ROOT for build:' cg@2596: "/ default:default. cg@2596: "/ cg@2596: "/ buildDirectory isEmptyOrNil ifTrue:[^ self]. cg@2596: "/ buildDirectory := buildDirectory asFilename. cg@2596: "/ directoryIsOKForMe := true. cg@2596: "/ cg@2596: "/ buildDirectory exists ifFalse:[ cg@2596: "/ Dialog warn:(self classResources string:'Work directory %1 does not exist.' with:buildDirectory). cg@2596: "/ directoryIsOKForMe := false. cg@2596: "/ ] ifTrue:[ cg@2596: "/ (buildDirectory construct:'stx') exists ifFalse:[ cg@2596: "/ Dialog warn:(self classResources stringWithCRs:'Work directory must contain an stx subDirectory,\which contains (at least) the stc and include subdirectories.'). cg@2596: "/ directoryIsOKForMe := false. cg@2596: "/ ] ifTrue:[ cg@2596: "/ stc := (OperatingSystem isMSDOSlike) ifTrue:['stc.exe'] ifFalse:['stc']. cg@2596: "/ (((buildDirectory construct:'stx')construct:'stc')construct:stc) exists ifFalse:[ cg@2596: "/ Dialog warn:(self classResources stringWithCRs:'Work directory must contain an stc compiler in the stx/stc subDirectory.'). cg@2596: "/ directoryIsOKForMe := false. cg@2596: "/ ]. cg@2596: "/ ((buildDirectory construct:'stx')construct:'include') exists ifFalse:[ cg@2596: "/ Dialog warn:(self classResources stringWithCRs:'Work directory must have had a make run before (for include files to exists).'). cg@2596: "/ directoryIsOKForMe := false. cg@2596: "/ ]. cg@2596: "/ ] cg@2596: "/ ]. cg@2596: "/ directoryIsOKForMe cg@2596: "/ ] whileFalse cg@2596: ! ! cg@2596: cg@2596: !ProjectBuilder class methodsFor:'documentation'! cg@2596: cg@2596: version_CVS cg@2596: ^ '$Header$' cg@2596: ! !