summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Mitz <mitza-oci@users.noreply.github.com>2010-12-22 17:36:26 +0000
committerAdam Mitz <mitza-oci@users.noreply.github.com>2010-12-22 17:36:26 +0000
commita399cf075c134b906526c09c2ad8a2348dadb5bf (patch)
tree81b4fe7b5864eea2292f514c53bffb9cfe4d705d
parent34954baad53240c7e0dbba7bd95d01d4de9a8a35 (diff)
downloadMPC-a399cf075c134b906526c09c2ad8a2348dadb5bf.tar.gz
ChangeLogTag: Wed Dec 22 17:28:56 UTC 2010 Adam Mitz <mitza@ociweb.com>
-rw-r--r--ChangeLog51
-rwxr-xr-xdevtools/document_template.pl39
-rw-r--r--docs/README13
-rw-r--r--docs/USAGE6
-rw-r--r--docs/html/MakeProjectCreator.css9
-rw-r--r--docs/html/MakeProjectCreator.html93
-rw-r--r--docs/html/RpmSpec.html174
-rw-r--r--docs/html/rpmworkflow.dot29
-rw-r--r--docs/html/rpmworkflow.pngbin0 -> 29677 bytes
-rw-r--r--docs/templates/rpmspec.txt29
-rw-r--r--modules/Creator.pm25
-rw-r--r--modules/Driver.pm5
-rw-r--r--modules/Options.pm5
-rw-r--r--modules/Parser.pm3
-rw-r--r--modules/ProjectCreator.pm7
-rw-r--r--modules/RpmSpecProjectCreator.pm77
-rw-r--r--modules/RpmSpecWorkspaceCreator.pm383
-rw-r--r--modules/WorkspaceCreator.pm98
-rw-r--r--modules/mpc_debug.pm57
-rwxr-xr-xmwc.pl3
20 files changed, 1056 insertions, 50 deletions
diff --git a/ChangeLog b/ChangeLog
index c9c78a30..439998e6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/docs/USAGE b/docs/USAGE
index 930f4ab3..b7935918 100644
--- a/docs/USAGE
+++ b/docs/USAGE
@@ -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">&nbsp;&nbsp;}</p>
+ <p class="Code">&nbsp;</p>
+
+ <p class="Code">&nbsp;&nbsp;specific(rpmspec) {</p>
+
+ <p class="Code">&nbsp;&nbsp;&nbsp;&nbsp;rpm_version = 1.0</p>
+
+ <p class="Code">&nbsp;&nbsp;}</p>
+
<p class="Code">}</p>
<p class="Code">&nbsp;</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>&lt;%rpm_mpc_temp%&gt;</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
new file mode 100644
index 00000000..3a2de95a
--- /dev/null
+++ b/docs/html/rpmworkflow.png
Binary files differ
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;
diff --git a/mwc.pl b/mwc.pl
index 7b8ce205..f5b090f8 100755
--- a/mwc.pl
+++ b/mwc.pl
@@ -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.