Module: projects-protocol-internals Synopsis: Project manager protocol library Author: Andy Armstrong Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND /// Basic target define variable *default-compilation-mode* :: = #"tight"; define open abstract class () constant slot file-location :: , required-init-keyword: locator:; constant slot file-timestamp :: , required-init-keyword: timestamp:; end class ; define open abstract class () slot file-generated-files :: false-or() = #f, init-keyword: generated-files:; end class ; define open abstract class () constant slot build-file-information :: = make(); end class ; define open abstract primary class () constant slot target-project :: , required-init-keyword: project:; constant slot target-name :: , required-init-keyword: name:; slot target-subtargets :: , required-init-keyword: subtargets:; slot %files :: false-or() = #f; slot target-processor :: , required-init-keyword: processor:; slot target-operating-system :: , required-init-keyword: operating-system:; slot target-compilation-mode :: = *default-compilation-mode*, init-keyword: compilation-mode:; slot target-copy-sources? :: = *copy-canonical-sources?*, init-keyword: copy-sources?:; slot target-linker :: false-or() = #f, init-keyword: linker:; slot target-filename :: false-or() = #f, init-keyword: filename:; slot target-type :: = #"executable", init-keyword: target-type:; slot target-linker-options :: false-or() = #f, init-keyword: linker-options:; slot target-base-address-string :: false-or() = #f, init-keyword: base-address-string:; slot target-library-loose-bindings :: = #(), init-keyword: loose-bindings:; slot target-library-tight-bindings :: = #(), init-keyword: tight-bindings:; slot target-build-state :: false-or() = #f, init-keyword: build-state:; slot %targets :: false-or() = #f; slot target-debug-command :: false-or() = #f, init-keyword: debug-command:; slot target-debug-arguments :: false-or() = #f, init-keyword: debug-arguments:; slot target-debug-machine :: false-or() = #f, init-keyword: debug-machine:; slot target-debug-directory :: false-or() = #f, init-keyword: debug-directory:; slot target-start-function :: false-or() = #f, init-keyword: start-function:; constant slot target-source-records-table :: = make(); end class ; define method target-title (target :: ) => (title :: ) as-lowercase(as(, target.target-name)) end method target-title; /// Subtargets define method target-build-targets (target :: ) => (targets :: ) target.%targets | begin let targets :: = make(); local method do-targets (target :: ) => () do(do-targets, target.target-subtargets); add!(targets, target) end method do-targets; do-targets(target); target.%targets := targets end end method target-build-targets; define inline method do-build-targets (function :: , target :: ) => () do(function, target.target-build-targets) end method do-build-targets; /// Source files define open generic read-file-information (target :: , extension :: , file :: ) => (information :: ); define open generic generate-files (target :: , information :: ) => (files :: ); //--- We almost certainly want different targets to support different //--- sets of sources, but for now we just use the project sources. define method target-source-files (target :: ) => (source-files :: ) target.target-project.project-source-files end method target-source-files; define method target-files (target :: ) => (files :: ) target.%files | refresh-target-files(target) end method target-files; define method refresh-target-files (target :: , #key clean? :: = #f) => (files :: ) let project = target.target-project; let source-files :: = as(, target.target-source-files); let files :: = make(); let dylan-extension = as(, dylan-file-extension()); while (~empty?(files)) block () let source-file :: = pop(source-files); let file = refresh-file-information(target, source-file, clean?: clean?); let generated-files = file.file-generated-files | begin file.file-generated-files := generate-files(target, file) end; for (source-file in generated-files using backward-iteration-protocol) push(source-files, source-file) end; add!(files, file) exception (error :: ) let location = error.condition-locator; build-serious-warning (project, "Skipping %s: %s", if (location.locator-base) location.locator-name else as(, location) end, error.condition-to-string) end end; target.%files := files end method refresh-target-files; define method do-target-files (function :: , target :: , #key type :: false-or(subclass()) = #f) let files = target.target-files; do(method (file :: ) if (~type | instance?(file, type)) function(file) end end, files) end method do-target-files; define method refresh-file-information (target :: , file :: , #key clean? :: = #f) => (information :: ) let information = target-source-file-information(target, file); if (clean? | begin let timestamp = information.file-timestamp; timestamp < file-property(file, #"modification-date") end) let type = file.locator-extension-type; target-source-file-information(target, file) := read-file-information(target, type, file) else file end end method refresh-file-information; define method target-source-file-information (target :: , file :: ) => (information :: false-or()) let build = target.target-build-state; if (build) let table = build.build-file-information; element(table, file, default: #f) end end method target-source-file-information; define method target-source-file-information-setter (information :: , target :: , file :: ) => (information :: ) let build = target.target-build-state; assert(build, "Setting source file information with no build state!"); let table = build.build-file-information; element(table, file) := information end method target-source-file-information-setter; /// Source records define constant = ; define constant = ; define method target-source-records (target :: ) => (source-records :: ) let project = target.target-project; let copy-sources? = target.target-copy-sources?; let files = target.target-files; let source-records :: = make(); let directory = case copy-sources? => target.target-build-directory; otherwise => project.project-directory; end; do-target-files (method (file :: ) let source-location = file.file-location; let location = case copy-sources? => source-location.locator-name; otherwise => source-location; end; do(method (id :: ) add!(source-records, target-id-source-record(target, id)) end, file-source-record-ids(, directory, location)) end, target, type: ); source-records end method target-source-records; define method target-id-source-record (target :: , id :: ) => (source-record :: ) let table = target.target-source-records-table; element(table, id, default: #f) | begin let project = target.target-project; let directory = project.project-directory; let record = id-as-source-record(, project, directory, id); element(table, id) := record end end method target-id-source-record;