Subversion Repositories gelsvn

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
107 bj 1
package AutomakeWorkspaceCreator;
2
 
3
# ************************************************************
4
# Description   : A Automake Workspace (Makefile) creator
5
# Author        : J.T. Conklin & Steve Huston
6
# Create Date   : 5/13/2002
7
# ************************************************************
8
 
9
# ************************************************************
10
# Pragmas
11
# ************************************************************
12
 
13
use strict;
14
 
15
use AutomakeProjectCreator;
16
use WorkspaceCreator;
17
use WorkspaceHelper;
18
 
19
use vars qw(@ISA);
20
@ISA = qw(WorkspaceCreator);
21
 
22
# ************************************************************
23
# Data Section
24
# ************************************************************
25
 
26
my($acfile)  = 'configure.ac';
27
my($acmfile) = 'configure.ac.Makefiles';
28
 
29
# ************************************************************
30
# Subroutine Section
31
# ************************************************************
32
 
33
sub workspace_file_name {
34
  my($self) = shift;
35
  return $self->get_modified_workspace_name('Makefile', '.am');
36
}
37
 
38
 
39
sub workspace_per_project {
40
  #my($self) = shift;
41
  return 1;
42
}
43
 
44
 
45
sub pre_workspace {
46
  my($self) = shift;
47
  my($fh)   = shift;
48
  my($crlf) = $self->crlf();
49
 
50
  print $fh '##  Process this file with automake to create Makefile.in', $crlf,
51
            '##', $crlf,
198 bj 52
            '## ', '$', 'Id', '$', $crlf,
107 bj 53
            '##', $crlf,
54
            '## This file was generated by MPC.  Any changes made directly to', $crlf,
55
            '## this file will be lost the next time it is generated.', $crlf,
56
            '##', $crlf,
57
            '## MPC Command:', $crlf,
58
            "## $0 @ARGV", $crlf, $crlf;
59
}
60
 
61
 
62
sub write_comps {
63
  my($self)          = shift;
64
  my($fh)            = shift;
65
  my($creator)       = shift;
66
  my($toplevel)      = shift;
67
  my($projects)      = $self->get_projects();
68
  my(@list)          = $self->sort_dependencies($projects);
69
  my($crlf)          = $self->crlf();
70
  my(%unique)        = ();
71
  my(@dirs)          = ();
72
  my(@locals)        = ();
73
  my(%proj_dir_seen) = ();
74
  my($have_subdirs)  = 0;
75
  my($outdir)        = $self->get_outdir();
76
 
77
  ## This step writes a configure.ac.Makefiles list into the starting
78
  ## directory. The list contains of all the Makefiles generated down
79
  ## the tree. configure.ac can include this to get an up-to-date list
80
  ## of all the involved Makefiles.
81
  my($mfh);
82
  if ($toplevel) {
83
    if (! -e "$outdir/$acfile") {
84
      my($acfh) = new FileHandle();
85
      if (open($acfh, ">$outdir/$acfile")) {
86
        print $acfh "AC_INIT(", $self->get_workspace_name(), ", 1.0)$crlf",
87
                    "AM_INIT_AUTOMAKE([1.9])$crlf",
88
                    $crlf,
89
                    "AC_PROG_CXX$crlf",
90
                    "AC_PROG_CXXCPP$crlf",
91
                    "AC_PROG_LIBTOOL$crlf",
92
                    $crlf,
93
                    "m4_include([$acmfile])$crlf",
94
                    $crlf,
95
                    "AC_OUTPUT$crlf";
96
        close($acfh);
97
      }
98
    }
99
    else {
100
      $self->information("$acfile already exists.");
101
    }
102
 
103
    unlink("$outdir/$acmfile");
104
    $mfh = new FileHandle();
105
    open($mfh, ">$outdir/$acmfile");
106
    ## The top-level is never listed as a dependency, so it needs to be
107
    ## added explicitly.
108
    print $mfh "AC_CONFIG_FILES([ Makefile ])$crlf";
109
  }
110
 
111
  ## If we're writing a configure.ac.Makefiles file, every seen project
112
  ## goes into it. Since we only write this at the starting directory
113
  ## level, it'll include all projects processed at this level and below.
114
  foreach my $dep (@list) {
115
    if ($mfh) {
116
      ## There should be a Makefile at each level, but it's not a project,
117
      ## it's a workspace; therefore, it's not in the list of projects.
118
      ## Since we're consolidating all the project files into one workspace
119
      ## Makefile.am per directory level, be sure to add that Makefile.am
120
      ## entry at each level there's a project dependency.
121
      my($dep_dir) = $self->mpc_dirname($dep);
122
      if (!defined $proj_dir_seen{$dep_dir}) {
123
        $proj_dir_seen{$dep_dir} = 1;
124
        ## If there are directory levels between project-containing
125
        ## directories (for example, at this time in
126
        ## ACE_wrappers/apps/JAWS/server, there are no projects at the
127
        ## apps or apps/JAWS level) we need to insert the Makefile
128
        ## entries for the levels without projects. They won't be listed
129
        ## in @list but are needed for make to traverse intervening directory
130
        ## levels down to where the project(s) to build are.
131
        my(@dirs) = split /\//, $dep_dir;
132
        my $inter_dir = "";
133
        foreach my $dep (@dirs) {
134
          $inter_dir = "$inter_dir$dep";
135
          if (!defined $proj_dir_seen{$inter_dir}) {
136
            $proj_dir_seen{$inter_dir} = 1;
137
            print $mfh "AC_CONFIG_FILES([ $inter_dir" . "/Makefile ])$crlf";
138
          }
139
          $inter_dir = "$inter_dir/";
140
        }
141
        print $mfh "AC_CONFIG_FILES([ $dep_dir" . "/Makefile ])$crlf";
142
      }
143
    }
144
 
145
    ## Get a unique list of next-level directories for SUBDIRS.
146
    ## To make sure we keep the dependencies correct, insert the '.' for
147
    ## any local projects in the proper place. Remember if any subdirs
148
    ## are seen to know if we need a SUBDIRS entry generated.
149
    my($dir) = $self->get_first_level_directory($dep);
150
    if (!defined $unique{$dir}) {
151
      $unique{$dir} = 1;
152
      unshift(@dirs, $dir);
153
    }
154
    if ($dir eq '.') {
155
      ## At each directory level, each project is written into a separate
156
      ## Makefile.<project>.am file. To bring these back into the build
157
      ## process, they'll be sucked back into the workspace Makefile.am file.
158
      ## Remember which ones to pull in at this level.
159
      unshift(@locals, $dep);
160
    }
161
    else {
162
      $have_subdirs = 1;
163
    }
164
  }
165
  if ($mfh) {
166
    close($mfh);
167
  }
168
 
169
  # The Makefile.<project>.am files append values to build target macros
170
  # for each program/library to build. When using conditionals, however,
171
  # a plain empty assignment is done outside the conditional to be sure
172
  # that each append can be done regardless of the condition test. Because
173
  # automake fails if the first isn't a plain assignment, we need to resolve
174
  # these situations when combining the files. The code below makes sure
175
  # that there's always a plain assignment, whether it's one outside a
176
  # conditional or the first append is changed to a simple assignment.
177
  #
178
  # We should consider extending this to support all macros that match
179
  # automake's uniform naming convention.  A true perl wizard probably
180
  # would be able to do this in a single line of code.
181
 
182
  my(%seen) = ();
183
  my(%conditional_targets) = ();
184
  my(%unconditional_targets) = ();
185
  my(%first_instance_unconditional) = ();
186
  my($installable_headers) = undef;
187
  my($installable_pkgconfig) = undef;
188
  my($includedir) = undef;
189
  my($project_name) = undef;
190
 
191
  ## To avoid unnecessarily emitting blank assignments, rip through the
192
  ## Makefile.<project>.am files and check for conditions.
193
  if (@locals) {
194
    my($pfh) = new FileHandle();
195
    foreach my $local (reverse @locals) {
196
      if ($local =~ /Makefile\.(.*)\.am/) {
197
        $project_name = $1;
198
      }
199
      else {
200
        $project_name = 'nobase';
201
      }
202
 
203
      if (open($pfh, "$outdir/$local")) {
204
        my($in_condition) = 0;
205
        my($regok)        = $self->escape_regex_special($project_name);
206
        my($inc_pattern)  = $regok . '_include_HEADERS';
207
        my($pkg_pattern)  = $regok . '_pkginclude_HEADERS';
208
        while (<$pfh>) {
209
          # Don't look at comments
210
          next if (/^#/);
211
 
212
          if (/^if\s*/) {
213
            $in_condition++;
214
          }
215
          if (/^endif\s*/) {
216
            $in_condition--;
217
          }
218
 
219
          if (   /(^[a-zA-Z][a-zA-Z0-9_]*_(PROGRAMS|LIBRARIES|LTLIBRARIES|LISP|PYTHON|JAVA|SCRIPTS|DATA|SOURCES|HEADERS|MANS|TEXINFOS))\s*\+=\s*/
220
              || /(^CLEANFILES)\s*\+=\s*/
221
              || /(^EXTRA_DIST)\s*\+=\s*/
222
             ) {
223
 
224
            if ($in_condition) {
225
              $conditional_targets{$1}++;
226
            } else {
227
              if (! $seen{$1} ) {
228
                $first_instance_unconditional{$1} = 1;
229
              }
230
              $unconditional_targets{$1}++;
231
            }
232
            $seen{$1} = 1;
233
 
234
            if (/^pkgconfig_DATA/) {
235
               $installable_pkgconfig= 1;
236
            }
237
            if (/^$inc_pattern\s*\+=\s*/ || /^$pkg_pattern\s*\+=\s*/) {
238
              $installable_headers = 1;
239
            }
240
          }
241
          elsif (/includedir\s*=\s*(.*)/) {
242
            $includedir = $1;
243
          }
244
        }
245
 
246
        close($pfh);
247
        $in_condition = 0;
248
      }
249
      else {
250
        $self->error("Unable to open $local for reading.");
251
      }
252
    }
253
  }
254
 
255
  #
256
  # Clear seen hash
257
  #
258
  %seen = ();
259
 
260
  ## Print out the Makefile.am.
261
  my($wsHelper) = WorkspaceHelper::get($self);
262
  my($convert_header_name) = undef;
263
  if ((!defined $includedir && $installable_headers)
264
      || $installable_pkgconfig) {
265
    if (!defined $includedir && $installable_headers) {
266
      my($incdir) = $wsHelper->modify_value('includedir',
267
                                            $self->get_includedir());
268
      if ($incdir ne '') {
269
        print $fh "includedir = \@includedir\@$incdir$crlf";
270
        $convert_header_name = 1;
271
      }
272
    }
273
    if ($installable_pkgconfig) {
274
       print $fh "pkgconfigdir = \@libdir\@/pkgconfig$crlf";
275
    }
276
 
277
    print $fh $crlf;
278
  }
279
 
280
  if (@locals) {
281
    my($status, $error) = $wsHelper->write_settings($self, $fh, @locals);
282
    if (!$status) {
283
      $self->error($error);
284
    }
285
  }
286
 
287
  ## If there are local projects, insert "." as the first SUBDIR entry.
288
  if ($have_subdirs == 1) {
289
    print $fh 'SUBDIRS =';
290
    foreach my $dir (reverse @dirs) {
291
      print $fh " \\$crlf        $dir";
292
    }
293
    print $fh $crlf, $crlf;
294
  }
295
 
296
  ## Now, for each target used in a conditional, emit a blank assignment
297
  ## and mark that we've seen that target to avoid changing the += to =
298
  ## as the individual files are pulled in.
299
  if (%conditional_targets) {
300
    my $primary;
301
    my $count;
302
 
303
    while ( ($primary, $count) = each %conditional_targets) {
304
      if (! $first_instance_unconditional{$primary}
305
          && ($unconditional_targets{$primary} || ($count > 1)))
306
      {
307
        print $fh "$primary =$crlf";
308
        $seen{$primary} = 1;
309
      }
310
    }
311
 
312
    print $fh $crlf;
313
  }
314
 
315
  ## Take the local Makefile.<project>.am files and insert each one here,
316
  ## then delete it.
317
  if (@locals) {
318
    my($pfh) = new FileHandle();
319
    my($liblocs) = $self->get_lib_locations();
320
    my($here) = $self->getcwd();
321
    my($start) = $self->getstartdir();
322
    foreach my $local (reverse @locals) {
323
 
324
      if (open($pfh, "$outdir/$local")) {
325
        print $fh "## $local", $crlf;
326
 
327
        my($look_for_libs) = 0;
328
 
329
        while (<$pfh>) {
330
          # Don't emit comments
331
          next if (/^#/);
332
 
333
          if ($convert_header_name) {
334
            if ($local =~ /Makefile\.(.*)\.am/) {
335
              $project_name = $1;
336
            }
337
            else {
338
              $project_name = 'nobase';
339
            }
340
            my($regok)       = $self->escape_regex_special($project_name);
341
            my($inc_pattern) = $regok . '_include_HEADERS';
342
            my($pkg_pattern) = $regok . '_pkginclude_HEADERS';
343
            if (/^$inc_pattern\s*\+=\s*/ || /^$pkg_pattern\s*\+=\s*/) {
344
              $_ =~ s/^$project_name/nobase/;
345
            }
346
          }
347
 
348
          if (   /(^[a-zA-Z][a-zA-Z0-9_]*_(PROGRAMS|LIBRARIES|LTLIBRARIES|LISP|PYTHON|JAVA|SCRIPTS|DATA|SOURCES|HEADERS|MANS|TEXINFOS))\s*\+=\s*/
349
              || /(^CLEANFILES)\s*\+=\s*/
350
              || /(^EXTRA_DIST)\s*\+=\s*/
351
             ) {
352
            if (!defined ($seen{$1})) {
353
              $seen{$1} = 1;
354
              s/\+=/=/;
355
            }
356
          }
357
 
358
          ## This scheme relies on automake.mpd emitting the 'la' libs first.
359
          ## Look for all the libXXXX.la, find out where they are located
360
          ## relative to the start of the MPC run, and relocate the reference
361
          ## to that location under $top_builddir. Unless the referred-to
362
          ## library is in the current directory, then leave it undecorated
363
          ## so the automake-generated dependency orders the build correctly.
364
          if ($look_for_libs) {
365
            my @libs = /\s+(lib(\w+).la)/gm;
366
            my $libcount = @libs / 2;
367
            for(my $i = 0; $i < $libcount; ++$i) {
368
              my $libfile = $libs[$i * 2];
369
              my $libname = $libs[$i * 2 + 1];
370
              my $reldir  = $$liblocs{$libname};
371
              if ($reldir) {
372
                if ("$start/$reldir" ne $here) {
373
                  my($mod) = $wsHelper->modify_libpath($_, $reldir, $libfile);
374
                  if (defined $mod) {
375
                    $_ = $mod;
376
                  }
377
                  else {
378
                    s/$libfile/\$(top_builddir)\/$reldir\/$libfile/;
379
                  }
380
                }
381
              }
382
              else {
383
                $self->warning("No reldir found for $libname ($libfile).");
384
              }
385
            }
386
            if ($libcount == 0) {
387
              $look_for_libs = 0;
388
            }
389
          }
390
          if (/_LDADD = \\$/ || /_LIBADD = \\$/) {
391
            $look_for_libs = 1;
392
          }
393
 
394
          print $fh $_;
395
        }
396
 
397
        close($pfh);
398
        unlink("$outdir/$local");
399
        print $fh $crlf;
400
      }
401
      else {
402
        $self->error("Unable to open $local for reading.");
403
      }
404
    }
405
  }
406
 
407
  ## If this is the top-level Makefile.am, it needs the directives to pass
408
  ## autoconf/automake flags down the tree when running autoconf.
409
  ## *** This may be too closely tied to how we have things set up in ACE,
410
  ## even though it's recommended practice. ***
411
  if ($toplevel) {
412
    print $fh $crlf,
413
              'ACLOCAL = @ACLOCAL@', $crlf,
414
              'ACLOCAL_AMFLAGS = -I m4', $crlf,
415
              'AUTOMAKE_OPTIONS = foreign', $crlf,
416
              $crlf;
417
  }
418
 
419
  ## Finish up with the cleanup specs.
420
  if (@locals) {
421
    ## There is no reason to emit this if there are no local targets.
422
    ## An argument could be made that it shouldn't be emitted in any
423
    ## case because it could be handled by CLEANFILES or a verbatim
424
    ## clause.
425
 
426
    print $fh '## Clean up template repositories, etc.', $crlf,
427
              'clean-local:', $crlf,
428
              "\t-rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.*",
429
              $crlf,
430
              "\t-rm -f gcctemp.c gcctemp so_locations *.ics", $crlf,
431
              "\t-rm -rf cxx_repository ptrepository ti_files", $crlf,
432
              "\t-rm -rf templateregistry ir.out", $crlf,
433
              "\t-rm -rf ptrepository SunWS_cache Templates.DB", $crlf;
434
  }
435
}
436
 
437
 
438
sub get_includedir {
439
  my($self)  = shift;
440
  my($value) = $self->getcwd();
441
  my($start) = $self->getstartdir();
442
 
443
  ## Take off the starting directory
444
  $value =~ s/$start//;
445
  return $value;
446
}
447
 
448
1;