diff options
author | Adam Mitz <mitza-oci@users.noreply.github.com> | 2010-12-22 17:36:26 +0000 |
---|---|---|
committer | Adam Mitz <mitza-oci@users.noreply.github.com> | 2010-12-22 17:36:26 +0000 |
commit | a399cf075c134b906526c09c2ad8a2348dadb5bf (patch) | |
tree | 81b4fe7b5864eea2292f514c53bffb9cfe4d705d | |
parent | 34954baad53240c7e0dbba7bd95d01d4de9a8a35 (diff) | |
download | MPC-a399cf075c134b906526c09c2ad8a2348dadb5bf.tar.gz |
ChangeLogTag: Wed Dec 22 17:28:56 UTC 2010 Adam Mitz <mitza@ociweb.com>
-rw-r--r-- | ChangeLog | 51 | ||||
-rwxr-xr-x | devtools/document_template.pl | 39 | ||||
-rw-r--r-- | docs/README | 13 | ||||
-rw-r--r-- | docs/USAGE | 6 | ||||
-rw-r--r-- | docs/html/MakeProjectCreator.css | 9 | ||||
-rw-r--r-- | docs/html/MakeProjectCreator.html | 93 | ||||
-rw-r--r-- | docs/html/RpmSpec.html | 174 | ||||
-rw-r--r-- | docs/html/rpmworkflow.dot | 29 | ||||
-rw-r--r-- | docs/html/rpmworkflow.png | bin | 0 -> 29677 bytes | |||
-rw-r--r-- | docs/templates/rpmspec.txt | 29 | ||||
-rw-r--r-- | modules/Creator.pm | 25 | ||||
-rw-r--r-- | modules/Driver.pm | 5 | ||||
-rw-r--r-- | modules/Options.pm | 5 | ||||
-rw-r--r-- | modules/Parser.pm | 3 | ||||
-rw-r--r-- | modules/ProjectCreator.pm | 7 | ||||
-rw-r--r-- | modules/RpmSpecProjectCreator.pm | 77 | ||||
-rw-r--r-- | modules/RpmSpecWorkspaceCreator.pm | 383 | ||||
-rw-r--r-- | modules/WorkspaceCreator.pm | 98 | ||||
-rw-r--r-- | modules/mpc_debug.pm | 57 | ||||
-rwxr-xr-x | mwc.pl | 3 |
20 files changed, 1056 insertions, 50 deletions
@@ -1,3 +1,54 @@ +Wed Dec 22 17:28:56 UTC 2010 Adam Mitz <mitza@ociweb.com> + + These changes were initially developed on the "rpmspec" branch. + + * modules/RpmSpecProjectCreator.pm: + * modules/RpmSpecWorkspaceCreator.pm: + + New type for generating RPM .spec files. + + * modules/Options.pm: + + Don't generate trailing whitespace in the list of types. + + * modules/Creator.pm: + + Extracted the =, +=, -= handling so it can be reused elsewhere. + + * modules/WorkspaceCreator.pm: + + Keep track of aggregated workspaces for use by some particular + WorkspaceCreators. Allow "specific" scopes within workspaces. + + * devtools/document_template.pl: + + Added ability to process templates embedded in Perl modules. + + * docs/USAGE: + + Added new types to the usage info for -type. + + * docs/README: + * docs/html/MakeProjectCreator.css: + * docs/html/MakeProjectCreator.html: + * docs/html/RpmSpec.html: + * docs/html/rpmworkflow.dot: + * docs/html/rpmworkflow.png: + * docs/templates/rpmspec.txt: + + Documented rpmspec type and "specific" scopes in workspaces. + + * modules/mpc_debug.pm: + + New Perl module to assist with debugging MPC. + + * modules/Driver.pm: + * modules/Parser.pm: + * modules/ProjectCreator.pm: + * mwc.pl: + + Use mpc_debug. + Mon Dec 20 18:55:04 UTC 2010 Adam Mitz <mitza@ociweb.com> * templates/vc10.mpd: diff --git a/devtools/document_template.pl b/devtools/document_template.pl index 49f68e68..d67d941d 100755 --- a/devtools/document_template.pl +++ b/devtools/document_template.pl @@ -39,7 +39,7 @@ require StringProcessor; my %keywords; my %arrow_op; my $doc_ext = '.txt'; -my $version = '1.3'; +my $version = '1.4'; # ****************************************************************** # Subroutine Section @@ -165,6 +165,8 @@ sub display_template { sub usageAndExit { print "document_template.pl v$version\n", "Usage: ", basename($0), " <template> [<outputfile> [language]]\n\n", + "template - .mpd file to document. Certain MPC types don't use a template,\n", + " in that case this argument can be the Perl module.\n", "outputfile - This defaults to the name of the template file with the .mpd\n", " extension replaced with '.html' If <outputfile> ends in '.txt',\n", " the output is in text format similar to what is found in\n", @@ -191,6 +193,7 @@ usageAndExit() if (!defined $input || $input =~ /^-/); if (!defined $output) { $output = $input; $output =~ s/\.mpd$//; + $output =~ s/(\w+)(Project|Workspace)Creator\.pm$/lc $1/e; $output .= '.html'; } elsif ($output =~ /\.txt$/) { @@ -214,11 +217,29 @@ if (open($fh, $input)) { } my %template_keys; - setup_keywords($language); - my @foreach; my $findex = -1; + + my $inputIsPerl = ($input =~ /\.pm$/); + my ($startPattern, $endPattern); + if ($inputIsPerl) { + my $pkg = basename($input); + $pkg =~ s/\.pm$//e; + require $input; + ($startPattern, $endPattern) = $pkg->documentation_info(\%keywords); + } + else { + setup_keywords($language); + } + my $skip = $inputIsPerl; + while(<$fh>) { + if ($inputIsPerl) { + $skip = 0 if ($skip && /$startPattern/); + $skip = 1 if (!$skip && /$endPattern/); + next if $skip; + } + my $len = length($_); for(my $start = 0; $start < $len;) { my $sindex = index($_, '<%', $start); @@ -301,6 +322,9 @@ if (open($fh, $input)) { $tvar = undef; } } + elsif (UNIVERSAL::isa($keywords{$name}, 'CODE')) { + ($name, $key, $vname, $tvar) = &{$keywords{$name}}($vname); + } } else { $def = $2; @@ -390,7 +414,14 @@ if (open($fh, $input)) { my $doc = $input; $doc =~ s/\.[^\.]+$/$doc_ext/; - $doc =~ s/templates/docs\/templates/; + if ($inputIsPerl) { + $doc =~ s/modules/docs\/templates/; + $doc =~ s/(\w+)(Project|Workspace)Creator$doc_ext$/lc($1) . $doc_ext/e; + } + else { + $doc =~ s/templates/docs\/templates/; + } + if (-r $doc) { $template_cp->read_file($doc); } diff --git a/docs/README b/docs/README index d3c9066e..5178103e 100644 --- a/docs/README +++ b/docs/README @@ -95,6 +95,10 @@ workspace { associate(other) { dir3 } + + specific(rpmspec) { + rpm_version = 1.0 + } } The associate scope associates a name with one or more directories. @@ -107,6 +111,15 @@ Currently automake is the only project type that supports associations. Each directory listed under an association is grouped together and built conditionally based on the association name. +Workspaces support a 'specific' clause conceptually and syntactically similar +to the project 'specific' clause, described below. Any variables assigned +within the clause are only available to workspaces, not to projects. Two sorts +of assignments are possible: first are assignments to the keywords cmdline and +implicit (described in the section 'Workspaces', below) and the second are +type-specific variables. Consult the documentation for the type for details on +type-specific variables. Keyword assignments (cmdline and implicit) impact the +entire workspace, not just the 'specific' scope. + Finally, prop:value are properties in MPC. They are used to group together common workspace/project types. More details on properties in MPC can be found in the section on the 'specific' keyword in the @@ -22,9 +22,9 @@ Usage: mwc.pl [-global <file>] [-include <directory>] [-recurse] [-gfeature_file <file name>] [-nocomments] [-for_eclipse] [-relative_file <file name>] [-language <cplusplus | csharp | java | vb>] - [-type <automake | bcb2007 | bcb2009 | bds4 | bmake | cc | em3 | - ghs |html | make | nmake | sle | vc6 | vc7 | vc71 | - vc8 |vc9 | vc10 | wb26>] + [-type <automake | bcb2007 | bcb2009 | bds4 | bmake | cc | cdt6 | + cdt7 | em3 | ghs | html | make | nmake | rpmspec | sle | + vc6 | vc7 | vc71 | vc8 | vc9 | vc10 | wb26 | wb30 | wix>] [files] -base Add <project> as a base project to each generated diff --git a/docs/html/MakeProjectCreator.css b/docs/html/MakeProjectCreator.css index 66b10c69..c9a9a84f 100644 --- a/docs/html/MakeProjectCreator.css +++ b/docs/html/MakeProjectCreator.css @@ -1711,3 +1711,12 @@ EM.zWhite { vertical-align: baseline; font-family: "Times New Roman"; } +img.floating { + float: right; + margin: lex; +} +pre.codeexample { + font-size: 8.0 pt; + font-family: "courier new"; + margin-left: 24 pt; +} diff --git a/docs/html/MakeProjectCreator.html b/docs/html/MakeProjectCreator.html index 0beb292c..fd586e56 100644 --- a/docs/html/MakeProjectCreator.html +++ b/docs/html/MakeProjectCreator.html @@ -215,6 +215,29 @@ <tr> <td rowspan="1" colspan="1"> + <p class="Tbl-Body"><em class="TableCode"> + <a href="CDT6.html">cdt6</a></em></p> + </td> + + <td rowspan="1" colspan="1"> + <p class="Tbl-Body">Eclipse CDT 6 (for Eclipse "Galileo" 3.5) + </p></td> + </tr> + + <tr> + <td rowspan="1" colspan="1"> + <p class="Tbl-Body"><em class="TableCode"> + <a href="CDT6.html"><!--CDT6.html describes cdt7 as well + -->cdt7</a></em></p> + </td> + + <td rowspan="1" colspan="1"> + <p class="Tbl-Body">Eclipse CDT 7 (for Eclipse "Helios" 3.6) + </p></td> + </tr> + + <tr> + <td rowspan="1" colspan="1"> <p class="Tbl-Body"><em class="TableCode">em3</em></p> </td> @@ -280,6 +303,17 @@ <tr> <td rowspan="1" colspan="1"> + <p class="TblCode"><em class="TableCode"> + <a href="RpmSpec.html">rpmspec</a></em></p> + </td> + + <td rowspan="1" colspan="1"> + <p class="Tbl-Body">RPM packaging .spec files.</p> + </td> + </tr> + + <tr> + <td rowspan="1" colspan="1"> <p class="TblCode"><em class="TableCode">sle</em></p> </td> @@ -331,7 +365,7 @@ <tr> <td rowspan="1" colspan="1"> - <p class="TblCode">vc9</p> + <p class="TblCode"><em class="TableCode">vc9</em></p> </td> <td rowspan="1" colspan="1"> @@ -341,7 +375,7 @@ <tr> <td rowspan="1" colspan="1"> - <p class="TblCode">vc10</p> + <p class="TblCode"><em class="TableCode">vc10</em></p> </td> <td rowspan="1" colspan="1"> @@ -351,7 +385,8 @@ <tr> <td rowspan="1" colspan="1"> - <p class="TblCode">wb26</p> + <p class="TblCode"><em class="TableCode"><a href="WB26.html"> + wb26</a></em></p> </td> <td rowspan="1" colspan="1"> @@ -361,6 +396,17 @@ <tr> <td rowspan="1" colspan="1"> + <p class="TblCode"><em class="TableCode"><a href="WB30.html"> + wb30</a></em></p> + </td> + + <td rowspan="1" colspan="1"> + <p class="Tbl-Body">Wind River Workbench 3.0.</p> + </td> + </tr> + + <tr> + <td rowspan="1" colspan="1"> <p class="Tbl-Body"><em class="TableCode">wix</em></p> </td> @@ -1410,6 +1456,14 @@ <p class="Code"> }</p> + <p class="Code"> </p> + + <p class="Code"> specific(rpmspec) {</p> + + <p class="Code"> rpm_version = 1.0</p> + + <p class="Code"> }</p> + <p class="Code">}</p> <p class="Code"> </p> @@ -1428,13 +1482,16 @@ This information would then be included in each workspace that inherits from it.</li> - <li class="Body">The lines between the curly braces contain - assignments, mpc files, directories, other workspace files or - exclusion sections. The mpc files listed will be included in the - workspace. If a directory is listed within the workspace, the - workspace creator will recursively traverse that directory and - use any mpc files that are found. If a workspace file is listed - it will be aggregated into the main workspace.</li> + <li class="Body">The lines between the curly braces + contain assignments, mpc files, directories, other + workspace files or exclusion sections. For each listed item, + <ul> + <li>an mpc file will be included in the workspace</li> + + <li>a directory recursively traversed and any mpc files + found will be included</li> + <li><a name="AggregatedWorkspace"></a>a workspace file will be aggregated into the main workspace.</li> + </ul> <li class="Body">A workspace can have assignments interspersed within the directories and mpc files. These assignments modify @@ -1469,6 +1526,20 @@ define specific workspaces, but the MPC defaults are sufficient for the directories involved within the workspace.</li> + <li class="Body"><a name="workspaceSpecific"></a>Workspaces + support a <em class="Code">specific</em> clause + conceptually and syntactically similar to <a + href="#projectSpecific">the project <em + class="Code">specific</em> clause.</a> Any variables + assigned within the clause are only available to + workspaces, not to projects. Two sorts of assignments are + possible: first are assignments to the keywords + <em class="Code">cmdline</em> and <em class="Code">implicit</em> + and the second are type-specific variables. Consult the + documentation for the type for details on type-specific variables. + Keyword assignments impact the entire workspace, not just the + <em class="Code">specific</em> scope.</li> + <li class="Body">Scoped assignments are assignments that are associated with specific mpc files or directories listed with the scope of the assignment. The following example shows a scoped @@ -2434,7 +2505,7 @@ </div> <div> - <h6 class="Head5">Specific Clause</h6> + <h6 class="Head5"><a name="projectSpecific">Specific Clause</a></h6> <ul> <li class="BodyNoLead">The <em class="Code">specific</em> diff --git a/docs/html/RpmSpec.html b/docs/html/RpmSpec.html new file mode 100644 index 00000000..ac7ff322 --- /dev/null +++ b/docs/html/RpmSpec.html @@ -0,0 +1,174 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=us-ascii"> + <meta http-equiv="Content-Style-Type" content="text/css"> + <meta name="id" content= + "$Id$"> + <link rel="STYLESHEET" href="MakeProjectCreator.css" charset="ISO-8859-1" + type="text/css"> + + <title>MPC: RpmSpec Type</title> +</head> + +<body> +<div> + <h1 class="Head1">RpmSpec Type documentation</h1> + + <div> + <h3 class="Head2">Background/Abstract</h3> + <li class="body">The <em>RpmSpec Type</em> generates + <samp>.spec</samp> files suitable for use by the <samp><a + href="http://docs.fedoraproject.org/en-US/Fedora_Draft_Documentation/0.1/html/RPM_Guide/ch-rpmbuild.html">rpmbuild</a></samp> + utility to build and package. It additionally creates a Bourne + shell script that automates creation of source tarball and proper + dependency-order building/packaging of <samp>.spec</samp> files. + </li> + + <li class="body">The RpmSpec type refines the existing + <em>aggregated workspace</em> MPC concept, as well as introduces + the ability to have <samp>specific</samp> clauses inside + workspace declarations (<samp>.mwc</samp> files). Consequently, + workspace files utilizing these new features are not + backwards-compatible with prior releases of MPC.</li> + + <li class="body">Since RPM is primarily Linux-based, RpmSpec only + officially supports use on Linux-based systems. It <em>may</em> + work on platforms for which an RPM port exists, but such success + would be coincidental and neither intended, tested, nor + guaranteed.</li> + + </div> + + <div> + <h3 class="Head2">Pre-requisites</h3> + <ul> + <li class="body">The following software items are required and + in the execution path (as well as any of their respective dependencies): + <dl> + <dt>RPM</dt> + <dd>Minimum of version 4.7.1 recommended (not tested with + other versions).</dd> + <dt>Development toolchain</dt> + <dd>This can be the standard development toolchain. Packaging + for other architectures is supported if the toolchain in the path + is a cross-compiler for that architecture.</dd> + </dl> + </ul> + </div> + + <div> + <h3 class="Head2">Usage</h3> + The RpmSpec type refines an existing concept in MPC known as + <em><a + href="MakeProjectCreator.html#AggregatedWorkspace">aggregate + workspaces</a></em> to define package scopes. When + <code>mwc.pl</code> is run on a top-level workspace with + <code>-type rpmspec</code>, each aggregated workspace is presumed + to define the scope of a package that will become an RPM. + Inter-project dependencies that exist between any projects known to + the top-level workspace automatically turn into inter-package + dependencies in RPMs. + + <h4>Generic workflow</h4> + <div align="center"> + <img src="rpmworkflow.png" alt="rpm workflow"/> + <h6 align="center">Figure: RPM Workflow</h6> + </div> + Presuming <code>.mwc</code> files already exist: + <ol> + <li>Use the command <samp>mwc.pl -type rpmspec <em>top-level-workspace.mwc</em></samp> to generate + <code>.spec</code> files and <samp>*_rpm.sh</samp> builder script.</li> + + <li>Run the <code><em>top-level-workspace</em>_rpm.sh</code> + script to build/package.</li> + </ol> + </div> + + <div> + <h3 class="Head2">Notes</h3> + <h4><a name-"mwcnotes"></a>Notes on Creating Workspaces</h4> + <p>The RpmSpec type uses <a + href="MakeProjectCreator.html#AggregatedWorkspace">aggregate + workspaces</a> to define the scope of a package. In other words, + defining a package involves writing a <samp>.mwc</samp> file that + includes all the projects that should go into that package. + An additional <samp>.mwc</samp> file must be written for each + additional package. Finally, these <em>package</em> workspaces get + aggregated into a workspace. + + <p>RPM packages require extra information not needed by "normal" + MPC projects or workspaces. This information is defined in a + <samp>specific</samp> clause in the workspace for the + <samp>rpmspec</samp> type, e.g., + + <pre class="codeexample"> +// top-level workspace +workspace { + specific (rpmspec) { + rpm_version = 1.0 + rpm_release = 1 + } + package1.mwc + package2.mwc +} +</pre> + Details on the variables allowed in the <samp>specific</samp> + clause can be found in <a href="../templates/rpmspec.txt">the + <samp>$MPC_ROOT/docs/templates/rpmspec.txt</samp> file.</a> + + <p>If you use workspaces as a part of + building right now, you may wish to write additional + workspace files specifically for packaging via RPM. + + <h4><a name="rpmnotes"></a>Notes on Generated RPMs</h4> + <ol> + <li>RPMs are relocatable using the <code>--prefix</code> or + <code>--relocate</code> options to <code>rpm</code>.</li> + <li>The RpmSpec type has no control over where the RPM system performs + it's "work" (building, staging, + packaging, etc.). In the + past, this was often <samp>/usr/src/redhat</samp>, though your + system may be configured differently.<br/><samp>rpmbuild</samp> + holds this directory in its <em>_topdir</em> configuration + variable. To see the value of <em>_topdir</em> on + your system, execute the following command:<br/> + <pre class="codeexample"> +<b>$ rpmbuild --showrc | grep '_topdir[^}]'</b> +-14: _topdir %{getenv:HOME}/rpmbuild +</pre> + </li> + + <li>Binary RPMs land in <samp><em>_topdir</em>/RPMS</samp>.</li> + <li>Source RPMs land in <samp><em>_topdir</em>/SRPMS</samp>.</li> + </ol> + + <h4><a name="scriptnotes"></a>Notes on Generated Script</h4> + <ol> + <li>The script takes one optional argument + indicating the architecture for which it should create packages. + The script makes no attempt to "find" a toolchain for that + architecture, instead presuming that whatever toolchain is + needed can be found in the PATH or is specified in the + <code>.spec</code> file.</li> + + <li>The script performs a build/install activity for each package. + Installation is not into the running system, but rather into a + "fake" area. Installation is necessary to satisfy inter-package + dependency requirements.<br/>The location of the "fake" area + defaults to <samp>/tmp/mpcrpm</samp> but can be changed by setting the + <samp><%rpm_mpc_temp%></samp> in a workspace + <samp>specific</samp> clause, typically in the top-level + workspace.</li> + + + </ol> +</div> + + + +<hr> +<address></address> +<!-- hhmts start --> Last modified: Wed Dec 22 09:48:06 CST 2010 <!-- hhmts end --> +</body> </html> diff --git a/docs/html/rpmworkflow.dot b/docs/html/rpmworkflow.dot new file mode 100644 index 00000000..25fc7006 --- /dev/null +++ b/docs/html/rpmworkflow.dot @@ -0,0 +1,29 @@ +digraph rpmpackaging { + rankdir=LR; + + subgraph cluster_completeprocess { + // rpmbuild output + rpmbuild [shape="box"]; + + rpmbuild -> SRPM; + rpmbuild -> bRPM; + + + // inputs to rpmbuild + specfile -> rpmbuild ; + tarball -> rpmbuild ; + + mwc [shape="box" label="mwc.pl"]; + rpmscript [shape="box" label="*_rpm.sh script"]; + + mwc -> specfile; + mwc -> rpmscript; + rpmscript -> tarball; + + mwcfiles [label=".mwc files"]; + + mwcfiles -> mwc; + + + } +} diff --git a/docs/html/rpmworkflow.png b/docs/html/rpmworkflow.png Binary files differnew file mode 100644 index 00000000..3a2de95a --- /dev/null +++ b/docs/html/rpmworkflow.png diff --git a/docs/templates/rpmspec.txt b/docs/templates/rpmspec.txt new file mode 100644 index 00000000..3d7d20a1 --- /dev/null +++ b/docs/templates/rpmspec.txt @@ -0,0 +1,29 @@ +// +// Document template variables for -type rpmspec +// Please try to keep this alphabetically sorted. +// +env_check = Optional. Names of environment variables that must be set when the RPM is built. +makefile_generator = Script that will run in the %build section of the RPM spec file in order to generate makefiles. If the default is changed it should be a wrapper around mwc.pl and pass all relevant arguments to mwc.pl. +makefile_name_pattern = A shell wildcard pattern describing the makefiles created by makefile_generator. +makeflags = Additional flags to pass on the make command line in the %build section of the RPM spec file. +mkgen_args = Additional arguments to pass to the makefile_generator. +prebuild = Additional command to run in the %build section of the RPM spec (before makefile_generator). +rpm_autorequiresprovides = Sets the RPM spec AutoReqProv tag. +rpm_buildrequires = Optional. Sets the RPM spec BuildRequires tag. +rpm_description = Required. Sets the content of the %description section of the RPM spec file. Multiple lines can be separated by \n. +rpm_group = Required. Sets the RPM spec Group tag. +rpm_license = Sets the RPM spec License tag. +rpm_mpc_requires = Do not provide a value, it is filled in by the RpmSpecWorkspaceCreator. +rpm_mpc_temp = Temporary directory for "fake installing" RPMs to satisfy dependency requirements during building. +rpm_mpc_workspace = Do not provide a value, it is filled in by the RpmSpecWorkspaceCreator. +rpm_name = Do not provide a value, it is filled in by the RpmSpecWorkspaceCreator. +rpm_post_cmd = Sets the content of the %post section of the RPM spec file. +rpm_postun_cmd = Sets the content of the %postun section of the RPM spec file. +rpm_prefix = Sets the RPM spec Prefix tag. +rpm_preun_cmd = Sets the content of the %preun section of the RPM spec file. +rpm_provides = Optional. Sets the RPM spec Provides tag. +rpm_releasenumber = Required. Sets the RPM spec Release tag. +rpm_requires = Optional. Sets the RPM spec Requires tag. These values will be used in addition to dependencies that MPC already knows due to the 'after' assignments. +rpm_source_base = Sets the URL or path base of the RPM spec Source tag. The RPM tarball name will be appended so it should end with a slash. +rpm_summary = Required. Sets the RPM spec Summary tag. +rpm_version = Required. Sets the RPM spec Version tag. diff --git a/modules/Creator.pm b/modules/Creator.pm index 0f61aa7a..803db3c1 100644 --- a/modules/Creator.pm +++ b/modules/Creator.pm @@ -338,15 +338,7 @@ sub parse_scope { ## processing the assignment as we will be throwing the value ## away anyway. if (defined $type) { - if ($values[0] == 0) { - $self->process_assignment($values[1], $values[2], $flags); - } - elsif ($values[0] == 1) { - $self->process_assignment_add($values[1], $values[2], $flags); - } - elsif ($values[0] == -1) { - $self->process_assignment_sub($values[1], $values[2], $flags); - } + $self->process_any_assignment($flags, @values); } } else { @@ -369,6 +361,21 @@ sub parse_scope { } +sub process_any_assignment { + my($self, $flags, @values) = @_; + + if ($values[0] == 0) { + $self->process_assignment($values[1], $values[2], $flags); + } + elsif ($values[0] == 1) { + $self->process_assignment_add($values[1], $values[2], $flags); + } + elsif ($values[0] == -1) { + $self->process_assignment_sub($values[1], $values[2], $flags); + } +} + + sub base_directory { my $self = shift; return $self->mpc_basename($self->getcwd()); diff --git a/modules/Driver.pm b/modules/Driver.pm index 231c7cf6..b96ad603 100644 --- a/modules/Driver.pm +++ b/modules/Driver.pm @@ -12,6 +12,7 @@ package Driver; use strict; +use mpc_debug; use Options; use Parser; use Version; @@ -537,10 +538,13 @@ sub run { ++$loopTimes; if (!$loaded{$name}) { + mpc_debug::chkpnt_pre_creator_load($name); require "$name.pm"; + mpc_debug::chkpnt_post_creator_load($name); $loaded{$name} = 1; } my $file = $cfile; + mpc_debug::chkpnt_pre_creator_create($name); my $creator = $name->new($options->{'global'}, $options->{'include'}, $options->{'template'}, @@ -570,6 +574,7 @@ sub run { $options->{'gendot'}, $options->{'comments'}, $options->{'for_eclipse'}); + mpc_debug::chkpnt_post_creator_create($name); ## Update settings based on the configuration file $creator->set_verbose_ordering($cfg->get_value('verbose_ordering')); diff --git a/modules/Options.pm b/modules/Options.pm index b38bdd53..b4ae0c24 100644 --- a/modules/Options.pm +++ b/modules/Options.pm @@ -86,9 +86,12 @@ sub printUsage { print STDERR "\n$spaces "; $len = $olen + $klen; } + elsif ($i) { + print STDERR ' '; + } print STDERR $keys[$i]; if ($i != $#keys) { - print STDERR ' | '; + print STDERR ' |'; $len += 3; } } diff --git a/modules/Parser.pm b/modules/Parser.pm index bca6dccd..7a749691 100644 --- a/modules/Parser.pm +++ b/modules/Parser.pm @@ -13,6 +13,7 @@ package Parser; use strict; use FileHandle; +use mpc_debug; use OutputMessage; use StringProcessor; use DirectoryManager; @@ -71,6 +72,7 @@ sub read_file { my $status = 1; my $errorString; + mpc_debug::chkpnt_pre_read_file($input, $cache); $self->{'line_number'} = 0; if (open($ih, $input)) { $self->debug("Open $input"); @@ -109,6 +111,7 @@ sub read_file { $errorString = "Unable to open \"$input\" for reading"; $status = 0; } + mpc_debug::chkpnt_post_read_file($input, $cache, $status, $errorString); return $status, $errorString; } diff --git a/modules/ProjectCreator.pm b/modules/ProjectCreator.pm index f959dd5d..67235477 100644 --- a/modules/ProjectCreator.pm +++ b/modules/ProjectCreator.pm @@ -14,6 +14,7 @@ use strict; use FileHandle; use File::Path; +use mpc_debug; use Creator; use TemplateInputReader; use TemplateParser; @@ -454,6 +455,7 @@ sub process_assignment { if (defined $value) { if ($name eq 'after') { + mpc_debug::chkpnt_pre_after_keyword_assignment($name, $value, $assign, $calledfrom); ## Support dependency attributes. They may or may not be used by ## the project or workspace creator implementation. They are ## stored separately from the dependencies themselves. Also, note @@ -479,6 +481,7 @@ sub process_assignment { $value = $self->fill_type_name($value, $self->get_default_project_name()); } + mpc_debug::chkpnt_post_after_keyword_assignment($name, $value, $assign, $calledfrom); } ## If this particular project type does not consider the dollar sign @@ -670,7 +673,9 @@ sub begin_project { } ## Begin reading the parent + mpc_debug::chkpnt_pre_parse_base_project($file); $status = $self->parse_file($file); + mpc_debug::chkpnt_post_parse_base_project($file, $status); ## Take the base project file off of the parent stack pop(@{$self->{'reading_parent'}}); @@ -3312,7 +3317,7 @@ sub list_default_generated { foreach my $type (@$tags) { ## Only add generated files if the following is true: ## 1) The generating type is not the same as the receiving type. - ## 2) The receivng type is not "special" (unless it hasn't been + ## 2) The receiving type is not "special" (unless it hasn't been ## supplied by the user). ## 3) The receiving type is not user defined or it is user ## defined and has 'automatic_in' set to true. diff --git a/modules/RpmSpecProjectCreator.pm b/modules/RpmSpecProjectCreator.pm new file mode 100644 index 00000000..c5ab3745 --- /dev/null +++ b/modules/RpmSpecProjectCreator.pm @@ -0,0 +1,77 @@ +package RpmSpecProjectCreator; + +# ************************************************************ +# Description : An RPM .spec file Project Creator +# Author : Adam Mitz (OCI) +# Create Date : 11/23/2010 +# ************************************************************ + +# ************************************************************ +# Pragmas +# ************************************************************ + +use strict; +use File::Path; + +use ProjectCreator; + +use vars qw(@ISA); +@ISA = qw(ProjectCreator); + +# ************************************************************ +# Subroutine Section +# ************************************************************ + +sub project_file_extension { + return '.dummy'; +} + +# Don't actually write anything, just keep MPC internal data structures +# up-to-date as if it had been written. We don't want a .spec file for each +# MPC project because that is too fine-grained. See the corresponding +# workspace creator for the actual .spec file creation. +sub write_output_file { + my $self = shift; + my $tover = $self->get_template_override(); + my @templates = $self->get_template(); + @templates = ($tover) if (defined $tover); + + if (scalar @templates != 1) { + return 0, 'there should be only one template'; + } + + my $template = $templates[0]; + $self->{'current_template'} = $template; + + my $name = $self->transform_file_name($self->project_file_name(undef, + $template)); + $self->process_assignment('project_file', $name); + new TemplateParser($self)->collect_data(); + + if (defined $self->{'source_callback'}) { + my $cb = $self->{'source_callback'}; + my $pjname = $self->get_assignment('project_name'); + my @list = $self->get_component_list('source_files'); + if (UNIVERSAL::isa($cb, 'ARRAY')) { + my @copy = @$cb; + my $s = shift(@copy); + &$s(@copy, $name, $pjname, \@list); + } + elsif (UNIVERSAL::isa($cb, 'CODE')) { + &$cb($name, $pjname, \@list); + } + else { + $self->warning("Ignoring callback: $cb."); + } + } + + # Still need outdir since ProjectCreator::write_install_file (or similar) + # may depend on outdir existing before the WorkspaceCreator runs. + my $outdir = $self->get_outdir(); + mkpath($outdir, 0, 0777) if ($outdir ne '.'); + + $self->add_file_written($name); + return 1, ''; +} + +1; diff --git a/modules/RpmSpecWorkspaceCreator.pm b/modules/RpmSpecWorkspaceCreator.pm new file mode 100644 index 00000000..c49548fd --- /dev/null +++ b/modules/RpmSpecWorkspaceCreator.pm @@ -0,0 +1,383 @@ +package RpmSpecWorkspaceCreator; + +# ************************************************************ +# Description : An RPM .spec file Workspace Creator +# Author : Adam Mitz (OCI) +# Create Date : 11/23/2010 +# ************************************************************ + +# ************************************************************ +# Pragmas +# ************************************************************ + +use strict; +use File::Path; +use POSIX qw(strftime); + +use RpmSpecProjectCreator; +use WorkspaceCreator; + +use vars qw(@ISA); +@ISA = qw(WorkspaceCreator); + +# ************************************************************ +# Data Section +# ************************************************************ + +my $ext = '.spec'; # extension of files written by this WorkspaceCreator + +# ************************************************************ +# Subroutine Section +# ************************************************************ + +sub workspace_file_name { + my $self = shift; + return $self->get_modified_workspace_name($self->get_workspace_name(), $ext); +} + +# Called by document_template.pl +sub documentation_info { + shift; #ignore package name + my $keywords = shift; + %$keywords = ('apply' => \&interpret_keyword, 'cond' => \&interpret_keyword); + return '^sub get_template', '^EOT$'; +} + +# Called by document_template.pl +sub interpret_keyword { + my $vname = shift; + $vname = (split /,/, $vname)[0]; + return ($vname, $vname, $vname, undef); +} + +# Don't actually write the .spec file for the workspace. Instead just invoke +# the $func callback so that post_workspace() and other parts of the normal +# workspace processing are called. We don't want a .spec file for each MPC +# workspace because that is too course-grained. Instead, post_workspace() will +# create one .spec for each aggregated workspace inside the primary workspace. +# Using the workspace aggregation mechanism this way allows multiple .spec +# files per workspace with MPC deriving their dependencies based on the +# projects they contain. +sub write_and_compare_file { + my($self, $outdir, $oname, $func, @params) = @_; + &$func($self, undef, @params); + return undef; +} + +sub rpmname { + my($self, $mwc, $rpm2mwc, $check_unique) = @_; + my $outfile = $mwc; + $outfile =~ s/\.mwc$//i; + $outfile = $self->get_modified_workspace_name($outfile, $ext, 1); + my $base = $self->mpc_basename($outfile); + $base =~ tr/-/_/; # - is special for RPM, we translate it to _ + if ($check_unique && $rpm2mwc->{$base}) { + die "ERROR: Can't create a duplicate RPM name: $base for mwc file $mwc\n" . + "\tsee corresponding mwc file $rpm2mwc->{$base}\n"; + } + $rpm2mwc->{$base} = $mwc; + return $base; +} + +## helper functions for the mini-template language + +sub mtl_cond { + my($vars, $pre, $rep) = @_; + my @v; + return (@v = grep {$_} map {$rep->{lc $_}} split(' ', $vars)) ? "$pre@v" : ''; +} + +sub mtl_apply { + my($name, $subst, $rep) = @_; + return join("\n", map {my $x = $subst; $x =~ s!\$_!$_!g; $x} + split(' ', $rep->{lc $name})); +} + +sub mtl_var { + my($name, $default, $rep) = @_; + return defined $rep->{lc $name} ? $rep->{lc $name} : + (defined $default ? $default : ">>ERROR: no value for $name<<"); +} + +## end helper functions for the mini-template language + + +sub post_workspace { + my($self, $fh, $prjc) = @_; + + my $prjext = '\\' . # regexp escape for the dot that begins the extension + $prjc->project_file_extension(); + + my %rpm2mwc; # rpm name (basename of spec file) => aggregated mwc w/ path + my %mwc2rpm; # inverse of the above hash + my %proj2rpm; # project name (output of mpc) => rpm name that it belongs to + # first pass to build the hashes above + foreach my $agg (keys %{$self->{'aggregated_mpc'}}) { + my $rpm = $mwc2rpm{$agg} = $self->rpmname($agg, \%rpm2mwc, 1); + foreach my $m (@{$self->{'aggregated_mpc'}->{$agg}}) { + foreach my $p (@{$self->{'mpc_to_output'}->{$m}}) { + $proj2rpm{$p} = $rpm; + } + } + } + + if (0 == scalar keys %proj2rpm) { + # nothing to generate (no aggregated workspaces) + return; + } + + my $outdir = $self->get_outdir(); + my $now = strftime '%a %b %d %Y %H:%M:%S', localtime; + + my %assign = %{$self->get_assignment_hash()}; + $assign{'rpm_description'} =~ s/\\n\s*/\n/g # Allow the description to span + if exists $assign{'rpm_description'}; # multiple lines in the output + map {$_ = $self->process_special($_)} values %assign; + + # determine when this addtemp processing should actually occur + while (my($key, $arr) = each %{$self->get_addtemp()}) { + foreach my $val (@$arr) { + my $v = $val->[1]; + $v =~ s/\\n\s*/\n/g if $key eq 'rpm_description'; + $v = $self->process_special($v); + $self->process_any_assignment(\%assign, $val->[0], $key, $v); + } + } + + foreach my $agg (keys %{$self->{'aggregated_mpc'}}) { + my $name = "$outdir/$agg"; # $agg may contain directory parts + my $dir = $self->mpc_dirname($name); + my $base = $mwc2rpm{$agg}; + my $rpm = $base; + $rpm =~ s/$ext$//; + $name = "$dir/$base"; + mkpath($dir, 0, 0777) if ($dir ne '.'); + + my %rpm_requires; # keys are RPMs that this RPM depends on + my @projects; + foreach my $m (@{$self->{'aggregated_mpc'}->{$agg}}) { + my $projdir = $self->mpc_dirname($m); + foreach my $p (@{$self->{'mpc_to_output'}->{$m}}) { + my $proj = $p; + $proj =~ s/$prjext$//; + push @projects, $proj; + my $deps = $self->get_validated_ordering("$projdir/$p"); + foreach my $d (@$deps) { + my $rpmdep = $proj2rpm{$d}; + if (defined $rpmdep && $rpmdep ne $base) { + $rpm_requires{$rpmdep} = 1; + } + } + } + } + + # The hash %rep has replacement values for the template .spec file text, + # those values come from a few different sources, starting with the + # workspace-wide assignments, then let RPM-specific ones (from aggregated + # workspaces) override those, and finally add the ones known by MPC. + # process_special() handles quotes and escape characters. + + my %rep = %assign; + + while (my($key, $val) = each %{$self->{'aggregated_assign'}->{$agg}}) { + $val =~ s/\\n\s*/\n/g if $key eq 'rpm_description'; + $rep{$key} = $self->process_special($val); + } + + $rep{'rpm_name'} = $rpm; + $rep{'rpm_mpc_workspace'} = $self->mpc_basename($agg); + $rep{'rpm_mpc_requires'} = + join(' ', sort map {s/$ext$//; $_} keys %rpm_requires); + + my $fh = new FileHandle; + open $fh, ">$name" or die "can't open $name"; + my $t = get_template(); + + ## We have decided not to reuse the TemplateParser.pm, so this file has + ## its own little template language which is a subset of that one. + + ## <%cond(var1 [var2...], prefix)%> + ## Output the prefix text followed by the concatenated, space separated, + ## values of the variables (var1, var2, etc) only if at least one of + ## said values is non-empty. + $t =~ s/<%cond\(([\w ]+), (.+)\)%>/mtl_cond($1, $2, \%rep)/ge; + + ## <%perl(expr)%> + ## Evaluate an arbitrary perl expression, which can reference the normal + ## variable replacements (see <%var%>, below) as $rep{'name'}. + $t =~ s/<%perl\((.+)\)%>/join "\n", eval $1/ge; + + ## <%apply(listvar, text)%> + ## Treat the value of variable 'listvar' as a list (splitting on spaces) + ## and repeat the text for each element of the list, substituting $_ in + ## the text with the current list element. + $t =~ s/<%apply\((\w+), (.+)\)%>/mtl_apply($1, $2, \%rep)/ge; + + ## <%var(default)%> or <%var%> + ## Output the value of variable 'var', either with a default value or an + ## error if 'var' is unknown. If 'default' is enclosed in double-quotes, + ## they are ignored (for compatibility with TemplateParser). + $t =~ s/<%(\w+)(?:\("?([^)"]*)"?\))?%>/mtl_var($1, $2, \%rep)/ge; + + print $fh $t; + + # comment will go in the %changelog section of the .spec + $self->print_workspace_comment($fh, map {$_ . "\n"} ( + "* $now This file was generated by MPC.", + ' $Id$', + ' Any changes made directly to this file will', + ' be lost the next time it is generated.', + ' MPC Command:', ' ' . $self->create_command_line_string($0, @ARGV))); + close $fh; + } + + # write the script to build .rpm files from .spec files + my $fh = new FileHandle; + my $name = $outdir . '/' . $self->{'workspace_name'} . '_rpm.sh'; + open($fh, ">$name") or die "can't open $name"; + print $fh "#!/bin/sh\n"; + $self->print_workspace_comment($fh, map {$_ . "\n"} ( + '# RPM creation script for MPC-generated .spec files.', + "# $now", + '# This file was generated by MPC. Any changes made directly to', + '# this file will be lost the next time it is generated.', + '# $Id$', + '# MPC Command:', '# ' . $self->create_command_line_string($0, @ARGV))); + + my $script = get_script(); + my $temporary = $assign{'rpm_mpc_temp'}; + $script =~ s!/tmp/mpcrpm!$temporary!g if defined $temporary; + print $fh $script; + + my %seen; + foreach my $project ($self->sort_dependencies($self->get_projects(), 0)) { + my $rpm = $proj2rpm{$self->mpc_basename($project)}; + next if !defined $rpm; + if (!$seen{$rpm}) { + $seen{$rpm} = 1; + my $dir = $self->mpc_dirname($rpm2mwc{$rpm}); + $dir = ($dir eq '.' ? '' : "$dir/"); + print $fh "build $dir$rpm\n"; + } + } + + close $fh; + chmod 0755, $name; +} + + +sub get_template { + return <<'EOT'; +License: <%rpm_license("Freeware")%> +Version: <%rpm_version%> +Release: <%rpm_releasenumber%> +Source: <%rpm_source_base("")%><%rpm_name%>.tar.gz +Name: <%rpm_name%> +Group: <%rpm_group%> +Summary: <%rpm_summary%> +BuildRoot: %{_tmppath}/%{name}-%{version}-root +Prefix: <%rpm_prefix("/usr")%> +AutoReqProv: <%rpm_autorequiresprovides("no")%> +<%cond(rpm_buildrequires, BuildRequires: )%> +<%cond(rpm_mpc_requires rpm_requires, Requires: )%> +<%cond(rpm_provides, Provides: )%> + +%description +<%rpm_description%> + +%files -f %{_tmppath}/<%rpm_name%>.flist +%defattr(-,root,root) +%doc +%config + +%post +<%rpm_post_cmd()%> + +%preun +<%rpm_preun_cmd()%> + +%postun +<%rpm_postun_cmd()%> + +%prep +%setup -n <%rpm_name%>-<%rpm_version%> + +%build +<%apply(env_check, [ -z $$_ ] && echo Environment variable $_ is required. && exit 1)%> +rm -rf $RPM_BUILD_ROOT +<%prebuild()%> +<%makefile_generator(mwc.pl -type gnuace)%> -base install -value_project libpaths+=<%rpm_mpc_temp(/tmp/mpcrpm)%>/inst/lib -value_project includes+=<%rpm_mpc_temp(/tmp/mpcrpm)%>/inst/include <%mkgen_args()%> <%rpm_mpc_workspace%> +make <%makeflags()%> + +%install +if [ "$RPM_BUILD_ROOT" = "/" ]; then + echo "Build root of / is a bad idea. Bailing." + exit 1 +fi +rm -rf $RPM_BUILD_ROOT +export staging_dir=$RPM_BUILD_ROOT/install<%rpm_prefix("/usr")%> +mkdir -p $staging_dir +export pkg_dir=$RPM_BUILD_ROOT/<%rpm_name%>_dir +mkdir -p $RPM_BUILD_ROOT/<%rpm_name%>_dir +make INSTALL_PREFIX=${staging_dir} install +if [ -d ${staging_dir}/share/man ]; then + files=$(find ${staging_dir}/share/man -name '*.bz2') + if [[ "${files}" ]]; then echo "${files}" | xargs bunzip2 -q; fi + files=$(find ${staging_dir}/share/man -name '*.[0-9]') + if [[ "${files}" ]]; then echo "${files}" | xargs gzip -9; fi +fi +cp -a $RPM_BUILD_ROOT/install/* ${pkg_dir} +find ${pkg_dir} ! -type d | sed s^${pkg_dir}^^ | sed /^\s*$/d > %{_tmppath}/<%rpm_name%>.flist +find ${pkg_dir} -type d | sed s^${pkg_dir}^^ | sed '\&^/usr$&d;\&^/usr/share/man&d;\&^/usr/games$&d;\&^/lib$&d;\&^/etc$&d;\&^/boot$&d;\&^/usr/bin$&d;\&^/usr/lib$&d;\&^/usr/share$&d;\&^/var$&d;\&^/var/lib$&d;\&^/var/spool$&d;\&^/var/cache$&d;\&^/var/lock$&d;\&^/tmp/apkg&d' | sed /^\s*$/d | sed 's&^&%dir &' >> %{_tmppath}/<%rpm_name%>.flist +cp -a $RPM_BUILD_ROOT/*_dir/* $RPM_BUILD_ROOT +rm -rf $RPM_BUILD_ROOT/*_dir +rm -rf $RPM_BUILD_ROOT/install + +%clean +make realclean +find . -name '<%makefile_name_pattern(GNUmakefile*)%>' -o -name '.depend.*' | xargs rm -f + +%changelog +EOT +} + + +sub get_script { + return <<'EOT'; +RPM_TOP=`rpmbuild --showrc | grep ': _topdir\b' | sed 's/^.*: _topdir\s*//' | perl -pe's/%{getenv:(\w+)}/$ENV{$1}/g'` +START_DIR=`pwd` +TMP_DIR=/tmp/mpcrpm +DB_DIR=`rpmbuild --showrc | grep ': _dbpath\b' | sed 's/^.*: _dbpath\s*//' | perl -pe's/%\{(\w+)\}/$x = qx(rpmbuild --showrc | grep ": $1\\\b" | sed "s\/^.*: $1\\\s*\/\/"); chomp $x; $x/e'` +RPM_ARCH=${1-`uname -m`} +echo MPC RPM build script: output files will be placed in $RPM_TOP/RPMS +[ -z $MPC_ROOT ] && echo ERROR: MPC_ROOT must be set && exit 1 +rm -rf $TMP_DIR && mkdir $TMP_DIR && cp -a $DB_DIR $TMP_DIR/db || exit $? + +build () { + [ ! -r $1 ] && echo ERROR: File not found $1 && exit 1 + PKG_DIR=`dirname $1` + PKG=`basename ${1%.spec}` + cd $PKG_DIR + VER=`grep ^Version: $PKG.spec | sed 's/^Version: //'` + REL=`grep ^Release: $PKG.spec | sed 's/^Release: //'` + echo Building source .tar.gz for $PKG version $VER release $REL + rm -rf $TMP_DIR/$PKG-$VER + $MPC_ROOT/clone_build_tree.pl -b $TMP_DIR $PKG-$VER > /dev/null + cd $TMP_DIR + tar chzf $RPM_TOP/SOURCES/$PKG.tar.gz $PKG-$VER && rm -rf $PKG-$VER + cp $START_DIR/$PKG_DIR/$PKG.spec $RPM_TOP/SPECS + echo Running rpmbuild on $PKG.spec for arch $RPM_ARCH, see rpm-$PKG.log for details + rpmbuild -ba --target $RPM_ARCH $RPM_TOP/SPECS/$PKG.spec > $START_DIR/rpm-$PKG.log 2>&1 + if [ $? != 0 ]; then + echo rpmbuild of $PKG.spec failed. STOPPING. + exit $? + fi + echo Installing $PKG to the temporary area + rpm --ignorearch --dbpath $TMP_DIR/db --prefix $TMP_DIR/inst -iv $RPM_TOP/RPMS/$RPM_ARCH/$PKG-$VER-$REL.$RPM_ARCH.rpm || exit $? + cd $START_DIR +} + +EOT +} + +1; diff --git a/modules/WorkspaceCreator.pm b/modules/WorkspaceCreator.pm index ac2f1e96..f0fd5239 100644 --- a/modules/WorkspaceCreator.pm +++ b/modules/WorkspaceCreator.pm @@ -71,6 +71,9 @@ sub new { $self->{'exclude'} = {}; $self->{'associated'} = {}; $self->{'scoped_assign'} = {}; + $self->{'aggregated_mpc'} = {}; + $self->{'aggregated_assign'} = {}; + $self->{'mpc_to_output'} = {}; ## These are maintained/modified throughout processing $self->{$self->{'type_check'}} = 0; @@ -83,6 +86,7 @@ sub new { $self->{'ordering_cache'} = {}; $self->{'handled_scopes'} = {}; $self->{'scoped_basedir'} = undef; + $self->{'current_aggregated'} = undef; ## These are static throughout processing $self->{'coexistence'} = $self->requires_make_coexistence() ? 1 : $makeco; @@ -168,6 +172,9 @@ sub parse_line { $self->{'exclude'} = $self->{'orig_exclude'}; $self->{'associated'} = {}; $self->{'scoped_assign'} = {}; + $self->{'aggregated_mpc'} = {}; + $self->{'aggregated_assign'} = {}; + $self->{'mpc_to_output'} = {}; } $self->{$self->{'type_check'}} = 0; } @@ -296,12 +303,15 @@ sub aggregated_workspace { my $oline = $self->get_line_number(); my $tc = $self->{$self->{'type_check'}}; my $ag = $self->{'handled_scopes'}->{$aggregated}; + my $pca = $self->{'current_aggregated'}; my $psbd = $self->{'scoped_basedir'}; + my $prev_assign = $self->clone($self->get_assignment_hash()); my($status, $error, @values) = (0, 'No recognizable lines'); $self->{'handled_scopes'}->{$aggregated} = undef; $self->set_line_number(0); $self->{$self->{'type_check'}} = 0; + $self->{'current_aggregated'} = $file; $self->{'scoped_basedir'} = $self->mpc_dirname($file); ## If the directory name for the file is the current directory, we @@ -345,7 +355,14 @@ sub aggregated_workspace { } close($fh); + if ($status) { + $self->{'aggregated_assign'}->{$file} = + $self->clone($self->get_assignment_hash()); + $self->{'assign'} = $prev_assign; + } + $self->{'scoped_basedir'} = $psbd; + $self->{'current_aggregated'} = $pca; $self->{'handled_scopes'}->{$aggregated} = $ag; $self->{$self->{'type_check'}} = $tc; $self->set_line_number($oline); @@ -370,6 +387,9 @@ sub parse_scope { elsif ($name eq 'associate') { return $self->parse_associate($fh, $type); } + elsif ($name eq 'specific') { + return $self->parse_specific($fh, $type, $validNames, $flags, $elseflags); + } else { return $self->SUPER::parse_scope($fh, $name, $type, $validNames, $flags, $elseflags); @@ -607,6 +627,38 @@ sub parse_associate { } +sub parse_specific { + my($self, $fh, $typestr, $validNames, $flags, $elseflags) = @_; + my $types = $self->process_types($typestr); + my $wctype = $self->{'wctype'}; + my $matches = exists $types->{$wctype}; + + # $elseflags needs to be defined for Creator::parse_scope to allow "} else {" + $elseflags = {} unless defined $elseflags; + + # Assignments within 'specific' always go to the workspace-level assignment + # hash table instead of the $flags bound to the scope. + my $assign = $self->get_assignment_hash(); + + return $self->SUPER::parse_scope($fh, 'specific', $matches ? $wctype : undef, + $validNames, $matches ? ($assign, $elseflags) + : (undef, $assign)); +} + + +sub handle_unknown_assignment { + my $self = shift; + my $type = shift; + my @values = @_; + + if (defined $type) { + $self->process_any_assignment(undef, @values); + } + + return 1, undef; +} + + sub excluded { my($self, $file) = @_; @@ -649,6 +701,9 @@ sub handle_scoped_unknown { my $error; my $dupchk; + ## If $type is undef, we are in a skipped part of a specific block + return 1 unless defined $type; + if ($line =~ /^\w+.*{/) { if (defined $fh) { my @values; @@ -720,16 +775,7 @@ sub handle_scoped_unknown { } foreach my $file (@files) { - if (!$self->excluded($file)) { - if (defined $dupchk && exists $$dupchk{$file}) { - $self->information("Duplicate mpc file ($file) added by an " . - 'aggregate workspace. It will be ignored.'); - } - else { - $self->{'scoped_assign'}->{$file} = $flags; - push(@{$self->{'project_files'}}, $file); - } - } + $self->add_aggregated_mpc($file, $dupchk, $flags); } } else { @@ -741,16 +787,7 @@ sub handle_scoped_unknown { last if (!$status); } else { - if (!$self->excluded($expfile)) { - if (defined $dupchk && exists $$dupchk{$expfile}) { - $self->information("Duplicate mpc file ($expfile) added by an " . - 'aggregate workspace. It will be ignored.'); - } - else { - $self->{'scoped_assign'}->{$expfile} = $flags; - push(@{$self->{'project_files'}}, $expfile); - } - } + $self->add_aggregated_mpc($expfile, $dupchk, $flags); } } } @@ -760,6 +797,23 @@ sub handle_scoped_unknown { } +sub add_aggregated_mpc { + my($self, $file, $dupchk, $flags) = @_; + if (!$self->excluded($file)) { + if (defined $dupchk && exists $$dupchk{$file}) { + $self->information("Duplicate mpc file ($file) added by an " . + 'aggregate workspace. It will be ignored.'); + } + else { + $self->{'scoped_assign'}->{$file} = $flags; + push(@{$self->{'project_files'}}, $file); + push(@{$self->{'aggregated_mpc'}->{$self->{'current_aggregated'}}}, + $file) if defined $self->{'current_aggregated'}; + } + } +} + + sub search_for_files { my($self, $files, $array, $impl) = @_; my $excluded = 0; @@ -1325,6 +1379,8 @@ sub generate_project_files { $allprinfo{$prkey} = $gen_proj_info; $allliblocs{$prkey} = $gen_lib_locs; } + + push(@{$self->{'mpc_to_output'}->{$ofile}}, @$files_written); } $self->cd($cwd); $self->save_project_info($files_written, $gen_proj_info, @@ -1808,7 +1864,7 @@ sub sort_dependencies { ## created we may get multiple groups for the same directory. ## Put the projects in the order specified - ## by the project dpendencies. We only need to do + ## by the project dependencies. We only need to do ## this if there is more than one element in the array. if ($#list > 0) { ## If the parameter wasn't passed in or it was passed in diff --git a/modules/mpc_debug.pm b/modules/mpc_debug.pm new file mode 100644 index 00000000..7847f9cd --- /dev/null +++ b/modules/mpc_debug.pm @@ -0,0 +1,57 @@ +package mpc_debug; + +# ************************************************************ +# Description : Scope for declaring useful checkpoints in MPC. +# +# This package defines a scope for defining do-nothing +# subroutines. Names should suggest checkpoints in the +# execution of MPC, and the body of the function should +# be empty. Calls to these functions can be inserted into +# various locations inside MPC source code, and a developer +# can set breakpoints on these functions to make it +# easier to hone in on checkpoints. +# +# If a call is useful, but should only be enabled +# during debugging (e.g., it's on a critical path and +# could negatively affect performance) then one can +# simply comment out the call. +# +# For ease in finding calls, please always fully scope +# the call, e.g., mpc_debug::chkpnt_blah(); +# +# Author : Chris Cleeland +# Create Date : 14.Dec.2010 +# ************************************************************ + +# ************************************************************ +# Pragmas +# ************************************************************ + +use strict; + +# Checkpoints +# +# Please follow convention and begin each checkpoint name with +# the string "chkpnt_". Adherence will make it easier for +# another developer to locate all occurrences of checkpoints +# within code using a tool like `grep`. + +# Called in Driver's processing of *Creators +sub chkpnt_pre_creator_load { } +sub chkpnt_post_creator_load { } +sub chkpnt_pre_creator_create { } +sub chkpnt_post_creator_create { } + +# Called in special 'after' keyword processing +# in ProjectCreator::process_assignment +sub chkpnt_pre_after_keyword_assignment { } +sub chkpnt_post_after_keyword_assignment { } + +# Called in Parser::read_file +sub chkpnt_pre_read_file { } +sub chkpnt_post_read_file { } + +sub chkpnt_pre_parse_base_project { } +sub chkpnt_post_parse_base_project { } + +1; @@ -32,6 +32,9 @@ $basePath = VMS::Filespec::unixify($basePath) if ($^O eq 'VMS'); my $mpcpath = $basePath; unshift(@INC, $mpcpath . '/modules'); +# Has to be a require because it's in the modules directory. +require mpc_debug; + ## If the ACE_ROOT environment variable is defined and this version of ## MPC is located inside the directory to which ACE_ROOT points, we will ## assume that the user wanted the ACE specific version of this script. |