Cons FAQ Version 1.0 24 November 1999 Steven Knight knight@baldmt.com ------------------------------ Subject: 1. Overview 1.1. Introduction This FAQ contains information about the Cons software construction utility. Much of the information in this FAQ is based on submissions to the Cons mailing list, cons-discuss@eng.fore.com. To join the mailing list, send email to cons-discuss-request@eng.fore.com with the word subscribe in the body of the message. 1.2. Current Version of This FAQ The most recent and up-to-date version of this FAQ may always be found at: http://www.baldmt.com/cons-faq/current.html (HTML) http://www.baldmt.com/cons-faq/current.txt (text) Please check to make sure your question isn't already answered in the latest version before submitting a new question (or an addition or correction to this FAQ). 1.3. Copyright This document is copyright 1999 by Steven Knight (knight@baldmt.com). Individual items taken from the Cons mailing list are incorporated with the permission of the credited individuals. This document may be freely copied, redistributed or modified for any purpose and without fee, provided that this copyright notice is not removed or altered. Individual items from this document may be excerpted and redistributed without inclusion of the copyright notice. If you incorporate this FAQ in any commercial, salable, or for-profit collection or product, please be courteous and send a copy to the copyright holder. 1.4. Feedback Any and all feedback on this FAQ is welcome: corrections to existing answers, suggested new questions, typographical errors, better organization of questions, etc. Contact the author at knight@baldmt.com. 1.5. Credits Thanks to the following for their contributions to the Cons mailing list and this FAQ: Ron Aaron, Chris Bartz, Todd J. Derr, Brad M. Garcia, Johan Holmberg, Anthony Kolarik, John Macdonald, Gary Oberbrunner, Jeff Rosenfeld, Jochen Schwarze, Bob Sidebotham, Alex Smith, and Rajesh Vaidheeswarran. ------------------------------ Subject: 2. Table of Contents 1. Overview 1.1. Introduction 1.2. Current Version of This FAQ 1.3. Copyright 1.4. Feedback 1.5. Credits 2. Table of Contents 3. General Information 3.1. What is Cons? 3.2. Do I need to understand Perl to use Cons? 3.3. Where do I get Cons? 3.4. Is there a Cons mailing list or newsgroup? 3.5. Is the mailing list archived anywhere? 3.6. On what operating systems does Cons run? 3.7. Who wrote Cons? 3.8. Who maintains Cons? 3.9. Who owns the copyright to Cons? 3.10. How is Cons licensed? 4. Compatibility with make 4.1. Is Cons compatible with make? 4.2. Is there a Makefile-to-Cons or Cons-to-Makefile converter? 4.3. What are the advantages or disadvantages of Cons vs. Make? 4.4. How do I do something like 'make install' in Cons? 4.5. Does Cons support building in parallel, like make's -j option? 4.6. Does Cons support something like VPATH in make? 5. Installation Problems 5.1. Why can't Cons locate a loadable object for module MD5? 5.2. Why can't Cons locate Config.pm? 6. Execution Problems 6.1. Why do I sometimes get an error message when I interrupt Cons? 6.2. Why didn't Cons build anything when I ran it? 6.3. Why can't Cons execute my compiler? 6.4. Why doesn't Cons pass the user's environment to child processes? 6.5. Why didn't Cons execute its Build directive when I expected? 6.6. How do I tell Cons that a single command builds multiple targets? 6.7. How do I use different or multiple compilers? 6.8. Do I have to put a separate Conscript file in each subdirectory? 6.9. How do I build multiple software versions from a single source? 6.10. How can I build or install files above the top-level Construct file? 6.11. How do I link objects created in separate subdirectories? 7. Dependencies 7.1. How can I have Cons list the build dependencies? 7.2. Will Cons use C preprocessor statements to determine dependencies? 7.3. Shouldn't the platform be part of Cons' dependency analysis? 7.4. Shouldn't the executable path be part of Cons' dependency analysis? 8. Language Support 8.1. Does Cons support C? 8.2. Does Cons support C++? 8.3. Does Cons support Java? 8.4. Does Cons support Fortran? 9. Files 9.1. Can I glob filenames in Cons? 9.2. How does Cons install files? 9.3. How do I get Cons to install a file only if it doesn't exist at all? 9.4. Can I replace individual modules in a library? 9.5. How do I build shared libraries? 9.6. How can I share files between builds for different architectures? 9.7. How do I change the suffix for object files? 10. Windows NT 10.1. On Windows NT, how do I specify an absolute path name in CPPPATH? 10.2. How does Cons deal with case insensitivity in Windows NT? 10.3. How do I build a DLL using Cons? 11. Extending Cons 11.1. How do I submit a new feature to be added to Cons? 11.2. How do I add support for new file types (suffixes)? ------------------------------ Subject: 3. General Information 3.1. What is Cons? Cons is a software construction utility--that is, an alternative to "make". It is implemented as a Perl script, which gives it many powerful capabilities not found in other software construction systems. 3.2. Do I need to understand Perl to use Cons? No. The file formats used by Cons are Perl-like, but do not require specific knowledge of Perl to be useful. Of course, you can use Cons more powerfully if you know Perl well enough to be able to use its features. 3.3. Where do I get Cons? The Cons home page is: http://www.dsmit.com/cons/ Mirrors are available at: http://www.baldmt.com/cons/ http://members.home.com/garsh/cons/ The page contains information about downloading the latest version of Cons. Cons is also available on CPAN, but the CPAN version is not up-to-date. 3.4. Is there a Cons mailing list or newsgroup? The Cons mailing list is cons-discuss@eng.fore.com. To subscribe, send email to cons-discuss-request@eng.fore.com with the word subscribe in the body of the message. There is no Cons newsgroup on Usenet. (Not yet, anyway.) 3.5. Is the mailing list archived anywhere? Not as of October 1999. 3.6. On what operating systems does Cons run? Because it is implemented as a Perl script, Cons could conceivably run on any system that supports Perl. Cons is known to be in production use on FreeBSD, Linux, Solaris, SunOS, HPUX, AIX, IRIX, and Windows NT. 3.7. Who wrote Cons? Cons was originally written by Bob Sidebotham. Bob still participates on the mailing list from time to time, but is not the current maintainer. 3.8. Who maintains Cons? Cons is currently maintained by Rajesh Vaidheeswarran. Questions about Cons should be directed to the cons-dicuss@eng.fore.com mailing list, however. 3.9. Who owns the copyright to Cons? Cons is copyright Fore Systems, Bob's employer while he was developing Cons. 3.10. How is Cons licensed? Fore Systems makes Cons available under a license similar to the BSD license. Yes, you can use it without charge. ------------------------------ Subject: 4. Compatibility with make 4.1. Is Cons compatible with make? No. Cons uses a completely different format for its input files. 4.2. Is there a Makefile-to-Cons or Cons-to-Makefile converter? No. It would probably be more work than it's worth to write a converter, especially since Cons' approach of building everything from a single process at the top of the directory tree differs radically from the standard recursive use of Make. 4.3. What are the advantages or disadvantages of Cons vs. Make? Cons' advantages over make are covered in detail in its documentation. The main advantage for many is that Cons has better dependency analysis integrated directly into its build engine, which means that you never have to do the equivalent of a 'make clean' to make sure that everything was rebuilt properly. It's also much faster than Make for typical builds of large directory trees. The main disadvantage of Cons is that its Construct and Conscript files have some of Perl's syntax-heavy flavor, which can mean a steeper learning curve than some people will tolerate. It also currently lacks a flexible extension mechanism for new file types like Make's suffix rules. 4.4. How do I do something like 'make install' in Cons? One of the biggest differences between make and Cons is that, in Cons, specified build targets are *only* files or subdirectories in your tree. Cons doesn't have a way to specify a dummy target of "install" in a way that means, "I don't really want you to build anything called install, I just want you to install a bunch of stuff elsewhere in the tree." (This is covered in the Cons documentation under the heading "No ``special'' targets.") 4.5. Does Cons support building in parallel, like make's -j option? Not currently. Some experimental versions that support parallel builds are in various stages of development. 4.6. Does Cons support something like VPATH in make? Yes. The Repository feature and -r option provide functionality very similar to VPATH, although without some inconsistencies that make VPATH somewhat difficult to use. See the Cons documentation for details. ------------------------------ Subject: 5. Installation Problems 5.1. Why can't Cons locate a loadable object for module MD5? After installation, Cons might generate an error message similar to the following: $ cons -V Can't locate loadable object for module MD5 in @INC (@INC contains: /opt/perl/lib/sun4-solaris/5.00404 /opt/perl/lib /opt/perl/lib/site_perl/sun4-solaris /opt/perl/lib/site_perl .) at cons line XXX BEGIN failed--compilation aborted at cons line XXX. This is generally because the Perl MD5 module has not been properly installed; just the MD5.pm file alone is not enough. The "loadable object" Perl wants is a shared library generated by xsubpp, and may be generated by a doing a full installation (perl makefile.PL; make install) of the MD5 module. 5.2. Why can't Cons locate Config.pm? After installation, Cons might generate an error message similar to the following: $ cons -x Can't locate Config.pm in @INC at /usr/swlocal/lib/perl5/DynaLoader.pm line 18. BEGIN failed--compilation aborted at /usr/swlocal/bin/cons line 1964. This is because the Perl binary you're using does not have the MD5 module installed at all. The MD5 module should be installed as above. If there are multiple versions of Perl installed on your system, 'which perl' will give the perl binary that is being used. ------------------------------ Subject: 6. Execution Problems 6.1. Why do I sometimes get an error message when I interrupt Cons? Q: Why, when I kill Cons with ^C, does it print the following msg before exiting? cons: error in file "docs-spark/Conscript" (Undefined subroutine &sig::hash::END called at ./cons line XXX.) [Gary Oberbrunner , 16 April 1998] A: Perl. This comes up on p5p every once in a while. As I understand it, the problem is this: a signal can arrive between any two instructions, some signals must be at least partially dealt with at once. If perl was in the middle of an action such as malloc, it might not be safe to interrupt in the middle and then evaluate more perl code before returning to that original position. There are ideas floating around for dealing with it and lots of desire to have it dealt with, but it is not easy (not completely and correctly anyhow). [John Macdonald , 16 April 1998] 6.2. Why didn't Cons build anything when I ran it? A: You have to give it a target, usually a directory. Try perl cons.pl . (that's a dot at the end of the line). [Gary Oberbrunner , 12 May 1998] A: Alternatively, you can use the 'Default' function to specify one or more default targets to build when no targets are specified on the command line. The following in a Construct file: Default qw( . ); will mimic make's behavior of building the world by default. 6.3. Why can't Cons execute my compiler? Q: I tried to run the 'hello' example. My Construct is: $env = new cons( CC => 'gcc', ); Program $env 'hello', 'hello.c' When I type 'cons hello', I get this output: gcc -c hello.c -o hello.o gcc: installation problem, cannot exec `cpp': Invalid argument cons: *** [hello.o] Error 256 cons: errors constructing hello.o Which is strange, since I can *manually* type: gcc -c hello.c hello.o and it works just fine. I am guessing my PATH or GCC_EXEC_PREFIX is getting munged by 'cons', because : perl -e "system 'gcc -c hello.c hello.o'" works just fine too!!! [Ron Aaron , 13 May 1999] A: Cons does not pass the user's environment to the child processes that it forks to build the software. Anything you need or want to pass in from the user's environment must be done so explicitly. In practice, this isn't hard at all: $Env = new cons( ENV => { PATH => $ENV{PATH} . ":/bin:/usr/bin", USER => $ENV{USER}, } ); Create any other, subsidiary Cons environments using $Env->clone, and everything else in your build gets the PATH that you want. [Steven Knight , 13 May 1999] 6.4. Why doesn't Cons pass the user's environment to child processes? A: This is for purposes of repeatability, so the build won't work for me because I have some weird thing in my path (or some other weird env variable that might alter compiler behavior) and yet fail for everyone else. Cons wants you to explicity set the path to what you need it to be. Most folks use Make this way too, for the same reason. [Gary Oberbrunner , 13 May 1999] 6.5. Why didn't Cons execute its Build directive when I expected? Q: Yet another mechanism that I wanted to implement in CONS but failed was a build script for templates coded in different languages (locales). I have this directory structure: templates/ templates/en templates/fr where templates/ are my locale-independent templates and templates/Conscript says 'for each locale, build a locale-specific template' (but do not Install it). The individual locale's Conscript contains the Install directive. templates/Conscript: @Locales = ('en','fr'); @Sources = ('index.html'); foreach $Locale (@Locales) { Command $CONS qq($Locale), join(' ',@Sources), q(localize %<); Build qq($Locale/Conscript); } templates/en/Conscript: foreach $Source(<*.html>) { Install $CONS qq($BIN), qq($Source); } templates/en/Conscript: I thought that CONS will first look at templates/Conscript, run the above Command which will generate a set of files in templates/$Locale, and then Build templates/$Locale/Conscript which will Install the generated files into $BIN. This didn't work. Is there a correct/better way to accomplish this? [Alex Smith , 26 March 1999] A: Cons directives (Install, Build, Command) can be moderately counter-intuitive, because they're not "executed" at the time they're processed by perl. ("Build" is especially problematic, because it doesn't actually *perform* a build of anything, it just reads up the specified subsidiary Conscript files containing build instructions...) When the Cons directives are processed, they just set up the appropriate dependency tree and storing the proper build commands for all the targets in all the Construct+Conscript files. It's not until Cons is actually trying to build the targets specified on its command line (or in the Default method) that it does any "real work" of building or installing files. Fixing your example to generate an index.html file from an index.in file for each locale: templates/Conscript: @Locales = qw(en fr); foreach $Locale (@Locales) { Build qq($Locale/Conscript); } templates/en/Conscript: @Inputs = qw(index.in); foreach $Source (@Inputs) { ($target = $Source) =~ s/\.in$/.html/; # index.in => index.html Command $CONS qq($target), qq($Source), q(localize %<); Install $CONS qq($BIN), qq($target); } [Steven Knight , 27 March 1999] 6.6. How do I tell Cons that a single command builds multiple targets? A: Make the target of the Command (or other directive) be a reference to an array containing a list of the targets being built. This is most commonly done by enclosing the list in [square brackets]. In order, for a common example, to build target foo.class and bar.class files from a single invocation of the Java compiler on the input foo.java and bar.java files: @sources = qw(foo.java bar.java); @targets = qw(foo.class bar.class); Command $CONS [@targets], @sources, q(javac %<); A: Or, if you have more targets produced from a given set of sources... say, foo.java and bar.java producing foo.class bar.class and baz.class... then this would work for you... @sources = qw(foo bar); @targets = qw(foo bar baz); CompileJava $CONS [@targets], [@sources]; sub cons::CompileJava { my($cons, $tgt, $src) = @_; $cons->Command([map(("$_.class"), @$tgt)], map(("$_.java"), @$src), q(javac %< )); } [Rajesh Vaidheeswarran , 29 March 1999] 6.7. How do I use different or multiple compilers? A: For C, you need a different environment for each specifying what CC is: # C build environment $CONS = new cons(); $CONS_C = clone $CONS( CC => "gcc", CPPPATH => $my_cpppath, ); # C++ build environment $CONS_CPP = clone $CONS( CC => "gcc -x c++", CPPPATH => $my_cplusplus_cpppath, ); @c_sources = qw(a.c b.c c.c); @cpp_sources = qw(a.cc b.cc c.cc); Library $CONS_C "mylib.a", @c_sources; Library $CONS_CPP "mylib.a", @cpp_sources; [Rajesh Vaidheeswarran , 29 March 1999] 6.8. Do I have to put a separate Conscript file in each subdirectory? A: No. You could put all of the information about your entire directory tree in one top-level Construct file that uses relative path names for all file references. In practice, though, most people find it a lot more convenient to list the source files and build rules for a given subdirectory's constructions in that subdirectory. Your mileage may vary. [Steven Knight , 7 April 1999] 6.9. How do I build multiple software versions from a single source? Q: During one call to cons, we would like to build two versions of a single set of source. We need to direct one source directory to two destinations, since we have to have different object files. We found it a real hassle having to update two sets of very similar sources in separate directories and decided to fold them together and use preprocessor directives to control the compilation. I didn't find a simple way to do that. Instead, I just created a second set of source files (.cpp) in the same directory as the first, with different names. These source files simply #include their counterpart. Any cleaner solutions? [Anthony Kolarik , 3 May 1999] A: Well, in one of the projects at FORE, we build an embedded OS and the boot monitor (bootrom) mostly from the same set of sources. In another project, we build the exact same sources for a variety of platforms like sunos5, irix6, and other flavors of unix. In the first case, we need to build both as cross-compiled targets on the same host platform. In the second case, we will always compile the sources only for the target platform on itself. The second case is easier compared to the first, so I'll give you an idea of how we approached the first one. I can't cut and paste the Conscripts here due to the copyrights in them, but I can given you an idea of what you can do. # Trees $src = "#src"; $build = "#build"; $variant1 = "$build/var1"; $variant2 = "$build/var2"; Link $build => $src; # cons object for variant1 $cons1 = new cons(CFLAGS => '-DVARIANT1'); # cons object for variant2 $cons2 = new cons(CFLAGS => '-DVARIANT2'); # common sources @srcs = qw(a.c b.c c.c) # variant1 sources @var1src = qw(d.c) # variant2 sources @var2src = qw(e.c) # First Variant of Program `prog' Install $cons1 $variant1, map("$src/$_", @srcs, @var1src); Program $cons1 "$variant1/prog", map("$variant1/$_", @srcs, @var1src); # Second Variant of Program `prog' Install $cons2 $variant2, map("$src/$_", @srcs, @var2src); Program $cons2 "$variant2/prog", map("$variant2/$_", @srcs, @var2src); So, you'll find the final program in variant1 style in build/variant1/prog and in variant2 style in build/variant2/prog The second case is much easier since you need to just change your build tree to be dependent on the OS. chomp ($ostype = `uname`); $build = "#build/$ostype"; Link $build => $src; [Rajesh Vaidheeswarran , 3 May 1999] A: The Link directive can do exactly this when used with multiple build environments. One way is to define multiple Cons environments with different CFLAGS, and then Link+Build the subsidiary program with each environment in turn: $ cat Construct my $build1 = new cons ( CFLAGS => '-DVERSION=1' ); my $build2 = new cons ( CFLAGS => '-DVERSION=2' ); $Env = $build1; Export qw( Env ); Link 'build1' => 'src'; Build 'build1/Conscript'; $Env = $build2; Export qw( Env ); Link 'build2' => 'src'; Build 'build2/Conscript'; $ You need to assign each build environment to $Env in turn because that's the environment that the subsidiary 'src' directory's Conscript file is expecting to Import: $ cat src/Conscript # src/Conscript Import qw( Env ); Program $Env 'foo', 'foo.c'; $ Because the src directory is Linked twice, once each with the separate build environments, it gets "called" with a different -DVERSION option in each subdirectory. Then, the common .c file uses normal #if/#ifdef to figure out which VERSION is needed: $ cat src/foo.c /* * src/foo.c */ main() { #if VERSION == 1 printf("This is version 1\n"); #elif VERSION == 2 printf("This is version 2\n"); #else #error Must -DVERSION=1 or -DVERSION=2 when compiling! #endif } Put it all together, and the build looks like this: $ cons . cc -DVERSION=1 -c build1/foo.c -o build1/foo.o cc -o build1/foo build1/foo.o cc -DVERSION=2 -c build2/foo.c -o build2/foo.o cc -o build2/foo build2/foo.o $ build1/foo This is version 1 $ build2/foo This is version 2 $ Another variation on this theme would have separate build1/Conscript and build2/Conscript files, each defining their own environment and Linking to the top-level src directory. This is easier to manage if there is a large number of different build environment (or if the environments themselves are complicated). [Steven Knight , 3 May 1999] 6.10. How can I build or install files above the top-level Construct file? A: Cons doesn't know how to build things above its top-level directory. (This is implied by the canonical invocation method of "cons .", where the "." target is the current directory and everything below.) There are two possible workarounds: 1) Move your Construct file up two directories, and change your Link path appropriately: Link ".$OS" => 'sub/dir/src'; 2) Use absolute path names, which do let you build targets outside of the Construct tree. This isn't as relocatable as being able to use "../.." explicitly, but perhaps you can do something like: $pwd = DirPath '.'; ($up_two_dirs = $pwd) =~ s#/[^/]+/[^/]+$##; Link "$up_two_dirs/.$OS" => 'src'; That is, construct the proper absolute path name and strip the last two subdirectories. (The use of DirPath above gives you the "current directory" for the Construct or Conscript file.) [Steven Knight , 24 July 1999] 6.11. How do I link objects created in separate subdirectories? Q: If I build object files spread out in multiple directories, each generated by a separate Conscript file, how can I link them all together into another relocatable module? A: In each Conscript file, include a LinkedModule directive, similar to: LinkedModule $ENV "#lib/combined.o", qw ( source1.c source2.c object1.o ); The list of files will be different in each Conscript file, but cons will basically combine all of these lists together to create the final lib/combined.o file. [Brad M. Garcia , 19 August 1999] ------------------------------ Subject: 7. Dependencies 7.1. How can I have Cons list the build dependencies? The -d option does this. (Note that -d performs a build at the same time; there isn't currently a way to only list dependencies without building.) 7.2. Will Cons use C preprocessor statements to determine dependencies? No. Any change to a file, regardless of whether it's surrounded by a #ifdef, will change the file's MD5 signature and cause a rebuild of all targets that depend on that file. So cons may believe that a file depends upon more than it actually does. This shouldn't hurt anything. If cons can't actually find one of the files that it believes should be a dependency, it simply ignores it. 7.3. Shouldn't the platform be part of Cons' dependency analysis? Q: I'm trying to use Cons to build programs on several different platforms (Solaris, HP-UX, Linux, NT at least). I was somewhat surprised that that the following could happen: hpux% cons hello cc -c hello.c -o hello.o cc -o hello hello.o hpux% hpux% rlogin solaris solaris% solaris% cons hello cons: "hello" is up-to-date. Shouldn't the "platform" be part of the signatures in some way? [Johan Holmberg , 16 August 1999] A: I would prefer that it isn't. We do cross-compiles for the same target machine on several different host machine architectures. Having the platform NOT be part of the signature means we can start a build under Solaris and re-compile just the changes on a Linux box without rebuilding the whole system. [Brad M. Garcia , 16 August 1999] Q: Is there some simple way I can accomplish this myself? [Johan Holmberg , 16 August 1999] A: You can accomplish this yourself by adding a "Salt" statement to your Construct file, similar to the following: $host_type = `uname -s`; Salt($host_type); You can use whatever you want to use to distinguish your build platforms as an argument to Salt. [Brad M. Garcia , 16 August 1999] 7.4. Shouldn't the executable path be part of Cons' dependency analysis? Q: I'm trying to use Cons to build programs on several different platforms (Solaris, HP-UX, Linux, NT at least). I was somewhat surprised that that the following could happen: On HPUX I have two diffeent compilers named "cc", one in /usr/bin and one in /usr/ccs/bin. If I change my Construct file to %env = new cons()->copy(); $env{CC} = "ccc"; $env{ENV}{PATH} = "/usr/local/bin:/bin:/usr/bin"; $env = new cons(%env); then build hello, and then later change Construct to %env = new cons()->copy(); $env{CC} = "ccc"; $env{ENV}{PATH} = "/usr/ccs/bin:/usr/local/bin:/bin:/usr/bin"; $env = new cons(%env); then cons still thinks hello is up-to-date. Shouldn't the actual path to "cc" used in the command be part of the signature, insead of just "cc" as I suspect it is now? [Johan Holmberg , 16 August 1999] A: Perhaps. The dependency analysis for ".o" files could be modified so that it also depends upon the compiler executable file as well as the source files. I would rather have it implemented in this manner, rather than simply going by the file path. For now, you could simply use $env{ENV}{PATH} as part of the argument to the Salt command. [Brad M. Garcia , 16 August 1999] ------------------------------ Subject: 8. Language Support 8.1. Does Cons support C? Yes. Cons was originally written to do a better job than Make at compiling C projects, largely by integrating C dependency analysis into the build tool. 8.2. Does Cons support C++? Yes. Cons build environments have a SUFMAP by which Cons understands that C++ file suffixes (.cc, .cxx, .cpp) can be built using its internal C compiler object. 8.3. Does Cons support Java? Using Cons to build Java projects is possible, but not straightforward. Java has a number of characteristics that don't fit well with the Cons (and Make) model of creating a dependency tree to determine what needs rebuilding: -- Java dependency analysis is more complex than the simple #include scanning of C and C++, arising from the classes used by the code in addition to the import statements. -- As a result of the class dependencies present, the Java compiler may create or update multiple output class files and directories. -- Java may automatically rebuild class files, even if not explicitly given as an argument to the compiler. -- Java may read possibly obsolete class files from previous compiler runs. From the point of view of an outside build tool, the Java compiler is essentially unpredictable, creating or updating whatever files it decides need it. This makes it extremely difficult for a build tool such as Cons to decide what needs updating, or has been updated, by Java. One approach that has been suggested would extend cons to scan the output of the Java -depend -verbose command to build dependency lists. Some additional mechanism would need to be invented to store Cons signatures on classes that are stored in archives (jar or zip files). This solution does not exist today. An alternative approach that is already in use by Jochen Schwarze (Jochen.Schwarze@orthogon.de) is to use an intermediate script that passes a list of Java files to the javac compiler, and puts the output class files in a new temporary directory. The script then calls jar to pack the newly-generated class files into a single jar file, essentially sidestepping the dependency issue. A second script is then used to merge the multiple jar files generated by the first script into a single file. This approach fits Cons more readily because the first script acts somewhat like a meta-compiler, creating a single object from Java source files, and the second acts like a linker, creating a single executable from multiple "objects." The advantage to this approach is that it makes the builds very reliable, because there's no chance that an obsolete but unremoved class file will be incorporated into a build by the javac compiler. The disadvantage, however, is that there's no way to incrementally update a portion of a jar file, since from Cons' point of view, each is created atomically by a single call to the "compile" script. Jochen has offered in the past to make his scripts available, but he is very busy, so be patient and courteous if you ask him for them. 8.4. Does Cons support Fortran? Not natively. As distributed, Cons can only parse C/C++ files for include dependencies. You would need to use QuickScan to add Fortran-scanning capability to your own Construct/Conscript files. ------------------------------ Subject: 9. Files 9.1. Can I glob filenames in Cons? TO BE WRITTEN. (This issue has generated a lot of past mailing list discussion, and needs editing. Volunteers are invited.) 9.2. How does Cons install files? Cons will try to create a hard link to the file first. If that fails (because the installation directory is on a separate partition or physical drive), then Cons will copy the file. 9.3. How do I get Cons to install a file only if it doesn't exist at all? Q: I have the following command: Command $env ("$BIN/license.txt", "license.txt", "test -e %> || cp %< %>"); The intended result is "replace this file only if it doesn't exist at all in $BIN." But of course it doesn't work, because cons deletes the target before it runs my command, so it always does the copy. Bummer. Is there a way, short of a fake target that always runs, to do this? (BTW, what I *really* want is for it only to do the cp if %< is newer than %>, any idea how to do that? Anyway, the existence test is good enough for my application.) [Gary Oberbrunner , 6 October 1998] A: Assuming that license.txt is not a derived file, then would this do? system("cp license.txt $BIN") unless -e "$BIN/license.txt"; If license.txt is derived, then this won't do, since it will be done too soon (before the derivation of the file). [Bob Sidebotham , 6 October 1998] 9.4. Can I replace individual modules in a library? Q: I'm looking for a way to replace files in an existing library using cons. i.e. I have some library 'libfoo.a' containing 'bar.o' and 'baz.o'. I want to build my own version of 'bar.o' from 'bar.c' and then build a new 'libfoo.a' with the new 'bar.o' and the old 'baz.o'. Is there any easy way to accomplish this? The only way I've come up with so far (I haven't tried it, and it will be a hack regardless) is to extract all of the objects from the existing library and then repackage the whole thing, because cons wants to delete the existing library before it rebuilds it rather than just replacing the files. [Todd J. Derr , 29 October 1998] A: On most systems (Solaris, Irix at least) it is faster (sometimes by a lot) to rebuild the archive from the .os than to replace ones in the middle. This is a problem in general though with cons, in that it always deletes the target before running the command even if that's not what you'd like. [Gary Oberbrunner , 29 October 1998] A: To answer my own question... Does anyone see any problems with this approach? Command $CONS "libfoo.a", ( "/path/to/original/libfoo.a", Objects $CONS "bar.c", ), "cp %1 %>; %AR r %> %<; %RANLIB %>"; It seems to be doing exactly what I want it to do. :) a little messy maybe, but less so than trying to extract and re-archive everything. [Todd J. Derr , 29 October 1998] A: This is definitely the best approach, IMO. What this does is explicitly recognize that you have a source (the original archive) and a separate target. If you try to make the source and the target the same thing, the Cons model doesn't work. For example, if we added an option to Cons to tell it to not remove files, you still have a circular dependency: the signature of the derived file depends on the files that go into it. But in this case, your derived file depends upon the derived file itself. So it would force a re-derivation the next time... [Bob Sidebotham , 29 October 1998] 9.5. How do I build shared libraries? Q: The Library method is hard-wired to generate non-shared libraries (.a files). How can I build shared libraries (.sl files)? A: As a quick-and-dirty approach, you can use the Program method to build a shared library directly by setting appropriate values for CFLAGS, LINK and LDFLAGS: $slenv = $env->clone(CFLAGS => '-fPIC', LINK => 'gcc', LDFLAGS => '-shared'); Program $slenv "mydll.sl" "file1.o", "file2.o", ...; A: Try adding the function below to your Construct. Use just like Library. You must do the following to use it: - Set LINK,LDFLAGS, etc. in your slenv environment to include '-shared' as above. - Set SUFSHLIB to '.sl' - Set SUFLIBS to '.sl:.a' so the shared lib will be found as a dependency by your program. This will solve the problem you are having, assuming you are using -lmydll to link with your lib. ######################################################################## # SharedLibrary ######################################################################## # Usage: just like Library, but builds a shared lib. User must set # CFLAGS,LINK,LDFLAGS etc. to proper options for building a shared lib. sub cons::SharedLibrary { my($env) = shift; my($lib) = $dir::cwd->lookup(file::addsuffix(shift, $env->{SUFSHLIB})); my($libenv) = $env->_resolve($lib); $lib->bind(find build::command::link($libenv, $libenv->{LINKCOM}), $env->_Objects(map($dir::cwd->lookup($_), @_))); } [Gary Oberbrunner , 5 March 1999] 9.6. How can I share files between builds for different architectures? Q: I try to set up a build environment where several architectures are built in parallel, but certain targets (for example C files generated by yacc) should be shared between all architectures. When I try to do this, however, cons always rebuilds the shared targets. I found the reason is that cons includes the build command's time stamp into the target file signature, i.e. if you have a target like Command $CONS "y.tab.c", "a.y", "yacc a.y"; The signature of y.tab.c contains the command name "yacc" (without path) and the modification time of /usr/bin/yacc, /usr/ccs/bin/yacc or wherever yacc resides. In general, this is probably an advantage, because it forces a rebuild whenever new compiler versions are installed. Any ideas how to address this problem? One could wrap a simple perl or shell script around yacc. With the script belonging to the source code, the modification time of the script would be the same for all archi- tectures. But this is not exceptionally elegant ... [Jochen Schwarze , 8 May 1998] Ignore "/yacc\$"; But if you ever upgrade yacc, y.tab.c will not get rebuilt automatically. You might be better off by simply rebuilding y.tab.c for each platform, rather than trying to share it among all platforms. Another possibility is to create "fake" .consign files in the directories where yacc lives, and give every copy of yacc the exact same checksum. [Brad M. Garcia , 8 May 1998] 9.7. How do I change the suffix for object files? Q: I'm working on a Construct file which I am trying to set up for multiple compilers and environments. One of the compilers assumes that objects have a '.obj' ending, not '.o', and it tries to compile '.o' files. Needless to say, this is undesirable :-) Is there some way to inform cons that the default object extension should be obj? [Ron Aaron , 13 September 1999] A: Within the cons environment, re-define SUFOBJ: $ENV = new cons( ... SUFOBJ => '.o', ... ); [Brad M. Garcia , 13 September 1999] ------------------------------ Subject: 10. Windows NT 10.1. On Windows NT, how do I specify an absolute path name in CPPPATH? Q: How can you specify an absolute path name in NT in CPPPATH. I want CPPPATH to have something like v:\msvc42\include in it. I can't put the colon in there because that is the delimiter that CONS uses in the CPPPATH. But if I don't put it in there then CONS does something like cl /I\v\msvc42\include which doesn't work either. [Chris Bartz , 29 September 1998] A: In Cons version 1.4a2, you can make CPPPATH be an array reference: CPPPATH => [ "#v:\msvc42\include", "another directory", ... ] This is now the preferred way to specify a path; the old way is deprecated. (BTW, there's a bug (or feature, if you will), currently, in that you have to specify files with drive letters as top-relative names, by starting them with a "#"). [Bob Sidebotham , 29 September 1998] 10.2. How does Cons deal with case insensitivity in Windows NT? Q: I have a problem in NT because of the odd case-insensitivity of NT. If I have one .c file that '#includes "abc.h"' and another that '#include "ABC.H"', they are really including the same file (assuming the same directory or include path, etc.). NT remembers the case that was used to create the file so the filename might be "abc.H", or "Abc.h", whatever, but the name is case insensitive because no matter what case you use to open the file, it will work. But cons treats them as different. The real problem is where "abc.h" is generated or "Installed" into the location where the compiler will find it. The file is not created in time and/or it is deleted (i.e. unlinked from the Link directory). When scanning .c files for #includes, if I change all the include file names to lower case, then things behave as expected. [Chris Bartz , 19 October 1998] A: It seems that some sort of change to recognize case insensitivity would be a useful change for NT. It'd be best, however, to change the directory and file handling modules to generically convert all file names to lower case. [Bob Sidebotham , 19 October 1998] 10.3. How do I build a DLL using Cons? TO BE WRITTEN. (There is some mailing list discussion of this topic that needs editing, in case anyone cares to volunteer.) ------------------------------ Subject: 11. Extending Cons 11.1. How do I submit a new feature to be added to Cons? Submit your patch to the mailing list. Important: include an update to the POD documentation at the end of the Cons script. There are already too many undocumented features in Cons. Mailing list members may provide feedback. Barring objections, Rajesh Vaidheeswarran may incorporate your feature in a future Cons release. 11.2. How do I add support for new file types (suffixes)? Q: Cons is pretty has a lot of hard-wired knowledge about building linking object files and executable files from C code. Are there suffix rules for different kinds of source files, like make does? A: As long as you're willing to explicitly list all the targets to which your suffix rule will apply, you can use the following in your Construct: sub cons::SufRule { my($env, $frsuf, $tosuf, @srcs) = @_; my($rule) = pop @srcs; foreach (@srcs) { s/$frsuf$// || next; Command $env "$_$tosuf", "$_$frsuf", $rule; } } Then your Conscript can do things like so: $CONS = new cons; SufRule $CONS ".pl" => ".c", @INIT, '%PERL %< > %>'; which allows a bunch of C files to be generated from perl scripts, or SufRule {$CONS->clone(CFLAGS => "-dD -E")} ".c" => ".i", @SRCS, '%CCCOM'; which builds preprocessed versions of C files when I ask for them. [Jeff Rosenfeld , 17 April 1998]