[net.lang.c++] C++ installation on 4.3bsd

whm@megaron.UUCP (03/21/86)

I just installed C++ on our 4.3bsd VAXs and it didn't go too smoothly.
I looked through the accumulated news in this group and there seem to
be people that are running C++ on BSD systems and since there's been
no mention of any others having any trouble installing on BSD systems,
I was wondering if I managed to screw things up somehow.

The problems seemed to stem from differences in Sys5 and BSD make and sh.
For example, the instructions say to "make scratch" and issuing this
command executes the following:

    cd scratch;  CC=CC BSD=1 CCFLAGS="-O -DBSD"

Oops!  Looks like it got the variables set ok.  If it had only remembered
to do the make!  We've got the BRL Sys5 package and using its make got
around the problems with BSD make.  In the CC script itself, when run
with /bin/sh, you get a cryptic error about -a being an unrecognized
operator for "test".  Running with Sys5 sh fixes this.  Further along
in CC, the command "CC -o x x.c" eventually tries to do something like:

	cc -c -o x x..c
	mv x..o x.o

With BSD cc, the output file lands in "x", not x..o.  With Sys5 cc, the
output goes to x..o; -o is passed on to the loader (if called).

Also, there was no man page for CC other than the one included in the hardcopy
documentation.

Am I the only person who has encountered these problems with a BSD installation?
If not, does anybody have a CC that allows the BSD cc behavior?

jon@cit-vax.Caltech.Edu (Jonathan P. Leech) (03/24/86)

Summary:
Expires:
Sender:
Followup-To:

Organization : California Institute of Technology
Keywords: C++, porting, BSD, UTS, Sun, IBM


    WARNING: The following  is	a  LONG  (~440	lines)	message  about
problems and experiences porting C++.  Hit  'n'  now  unless  you  are
having problems getting the new release of C++ running.

    The following is a summary of my experiences porting  C++  Release
1.0 to three flavors of Unix on different  hardware  (VAX  11/780  4.2
BSD, Sun 2.0,  IBM  4381  Amdahl  UTS).   Not  everything  said  below
applies to all of the machines.  I cannot promise your	problems  will
be the same, because I don't know how heavily the environment  of  our
machines (or yours) has been  modified.   However,  this  material  is
accurate within these bounds and may  resolve  questions  some	people
have had about installing C++. (And, to forestall any  flames,	Bjarne
looked this over and approved it before I posted it).

I) Shell scripts

    A) ``What's this ':' doing here?'' or, how do you get the right shell?

	Different versions of  Unix  have  different  conventions  for
    identifing	shell  scripts.  Unfortunately	it   appears   to   be
    impossible to come up with a single Bourne Shell script file which
    can be used with impunity on all Unix variants. Here's my  summary
    of how systems deal with scripts:

	4.2 BSD (VAX)

	    Apparently all scripts are executed with sh  UNLESS  there
	is a line of the  form	'#!program'  where  'program'  is  the
	alternative  interpreter  (such  as  /bin/csh)	to  run.    No
	problems with the supplied scripts here.

	4.2 BSD (Sun release 2.0)

	    Apparently the default here is csh, not sh (my login shell
	is csh, which may be the cause) .  There is in fact a line  of
	the form '#!/bin/sh' in the 'CC' shell	script,  but  it's  on
	the SECOND line, so it's not recognized.  It must be moved  to
	the  first  line.  The	'bsd.sed'  shell  script  (if  there's
	occasion to run it) must have the '#!/bin/sh'  line  added  as
	the first line.

	Amdahl UTS

	    In order to get a script executed by sh on	this  variant,
	it needs to have a ':' as the first character of the file  (or
	at least this suffices). Even '#!/bin/sh' as  the  first  line
	does not do the desired thing. So CC must  be  edited  to  add
	this.

    B) Nobody bothered to test `test'.

	There is a problem with the 'CC' shell	script	on  many  Unix
    systems.  The 'test' program  is  used  in	CC  in	the  following
    context (towards the end of the script):

	    if	    test "$R" -a ! "$PLUSI"
	    then
		    rm $C
	    fi

	unfortunately, strings as operands to 'test' do not work quite
    right on (at least) 4.2 BSD derived systems.  In theory, an  empty
    string "" should be equivalent to '0' or 'false' and the  converse
    for a non-empty string. In	fact  this  only  works  if  the  ONLY
    argument to test is a SINGLE empty (or  not)  string.  To  observe
    this, execute

	test "" -a ""

    on a 4.2 system and cringe. This behavior has been seen on VAX/4.2
    BSD, Sun 4.2 BSD, VAX/4.3 BSD, and a version of Unix derived  from
    Unix/TS and Unix/32V. Test appears to work	properly  on  all  the
    System III/System V Unixes (Unices? Unixi?) that I have access to.

	To correct this problem, change the 4 lines above to

	    if test "$R" ; then
		if test ! "$PLUSI" ; then
		    rm $C
		fi
	    fi

	this is a bit more verbose, but works.

    C) But... how do you find the members?

	The source to cfront (the compiler portion of  C++)  comes  in
    both C++ and C form, the latter to provide a way of  bootstrapping
    cfront.  The C version of cfront appears  to  be  targeted	for  a
    System V Unix. In order to get cfront working properly  on	a  4.2
    BSD system (in fact on any Unix system), the  declaration  of  the
    'FILE' aka '_iobuf' structure must be changed to  correspond  with
    with that on your system. Otherwise cfront will explode the  first
    time it tries to do I/O.

	There is a supplied shell script 'bsd.sed'  in	the  'scratch'
    directory which is supposed to massage the C source to  cfront  by
    changing the declarations of FILE members. Unfortunately, it  does
    not do the complete job; the '__iobuf__flag' member of FILE  is  a
    SHORT on 4.2 BSD, not a char. This might (or  might  not)  make  a
    difference, depending on the byte order and alignment  constraints
    of the machine cfront is being compiled on.  The  following  shell
    script corrects the declaration of FILE; it should be run  in  the
    'scratch' directory AFTER bsd.sed.

	#!/bin/sh
	#ident	"@(#)cfront:scratch/bsd42.sed (jon@csvax.caltech.edu)  1.0"
	echo "Fixing _iobuf structures for 4.2 BSD (__iobuf__flag member):"
	for f in */*..c
	do
		echo $f
		sed -e '/__iobuf__flag/s/char/short/' $f > temp$$
		mv temp$$ $f
	done
	echo "We now return to our regularly scheduled C++ installation process"


II) OS/utility bugs

    A) exit() vs. return() or, ``I don't  CARE	what  you  said!   I'm
	exiting successfully anyway!''

	The 'CC' script uses the exit status of the program 'munch' to
    determine if another pass of  the  loader  needs  to  be  made  to
    properly call static constructors and destructors. Munch tries  to
    return this status by just doing 'return 0'  or  'return  1'  from
    main().  Unfortunately, on several Unix variants (at least Sun 4.2
    BSD and Amdahl UTS), ANY successful return	from  main  causes  an
    exit status of 0 instead of the returned value.  For  portability,
    change   all   'return   n'   to   'exit(n)'    in	  main()    of
    lib/static/munch.c.

    B) Optimization

	On UTS, the optimizer pass of the C  compiler  (/lib/c2)  core
    dumps  while  trying  to  compile  parts  of   the	 C++   library
    (specifically lib/complex/io.c). Rather than  try  to  figure  out
    why, I  just  removed  the	-O  flag  from	'lib/mk/makefile'  and
    'makefile'.  Bjarne   says	 that	many   optimizers   break   on
    automagically generated C code such as that produced by cfront.

    C) Makefiles

    i) UTS

	Some parts of the  supplied  makefiles	contain  Bourne  shell
    constructs.  On UTS, the  underlying  shell  that  is  invoked  by
    'make' is  normally  /bin/sh,  but	if  the  environment  variable
    'SHELL' is defined, that is used instead. If your login  shell  is
    NOT sh (say /usr/ucb/csh instead like mine), make  will  die  when
    it feeds sh commands to a csh.  Here are 2 solutions:

	(i) define SHELL=/bin/sh in the environment
	(ii) Add a line of the form  'MAKE=/bin/make  SHELL='  to  the
	    top-level makefile.  This will cause SHELL to be undefined
	    when lib/mk/makefile is invoked, so sh  will  be  used  as
	    desired. This is the preferred solution.

    ii) BSD

	When the top-level makefile invokes other makefiles,  it  uses
    the construct $(MAKE).  Unfortunately, MAKE is  NOT  a  predefined
    make variable in the 4.2 BSD implementation. To correct this,  add
    a line of the form

	MAKE=/bin/make

	at the start of the top-level makefile.

    D) Ranlib (BSD)

	When an archive library (such as the  libC.a  created  in  the
    bootstrapping process)  is	copied,  BSD  systems  sense  the  new
    modification date and complain that 'ranlib' has not been  run  on
    the archive since the copy. Ld will then exit with an  unwarranted
    error code, which causes 'CC' to bomb out early.  To correct this,
    once libC.a is installed in its final destination (/lib, /usr/lib,
    or whatever), re-run 'ranlib' on it.

    E) Dereferencing NULL

	This fix has been seen before but I'm putting it in for completeness.
    Make the following change in src/print.c:

diff print.c.new  print.c.orig
1452,1453c1452
<				if ( (e2->tp == 0) ||
<					Pptr(t1)->typ != Pptr(e2->tp)->typ) {
---
>				if (Pptr(t1)->typ != Pptr(e2->tp)->typ) {

III) Random comments on porting C++ to different target machines

    A) Portability of the supplied C code to cfront

	As  the  AT&T  installation  guide   briefly   mentions,   the
    declarations of the stdio FILE structure must be correct  for  the
    target system.  That is not the  only  problem,  however.	Cfront
    needs to know about size and  alignments  of  data	types  on  the
    target architecture in order to generate correct C code  for  said
    machine. WARNING: the supplied C code for cfront is only  promised
    to work on a 3B or VAX because of this.

	 The only way to get  around  this  is	to  first  get	cfront
    running on one of the machines the	C  code  WILL  work  on,  then
    cross-compile cfront (using an  appropriate  size/alignment  file)
    for the target machine.  Then you must move to the target  machine
    and restart the process from 'scratch' (so to speak).

    B) Cross-compiling

	This assumes that you already have a working version of CC  on
    some machine. If you don't, find some friendly person with	a  VAX
    or 3B.

	First, you have to find an appropriate size/alignment file for
    the target machine. Here are size/align files for  Sun  2  (68000)
    and Amdahl UTS (IBM 370 architecture):

	Sun:

	    char    1	1
	    short   2	2
	    int     4	2   2147483647
	    long    4	2
	    float   4	2
	    double  8	2
	    bit     8	32
	    struct  2	2
	    frame   2	2
	    top     0	0
	    word    4	0
	    wptr    4	2
	    bptr    4	2

	UTS:

	    char    1	1
	    short   2	2
	    int     4	4	2147483647
	    long    4	4
	    float   4	4
	    double  8	8
	    bptr    4	4
	    wptr    4	4
	    struct  1	1
	    ptr     4	4
	    bit     8	32
	    word    4	0

	In addition, you may need to modify the 'DF_SENSITIVE' #define
    in src/size.h; I believe this should be 0 for Suns and 1 for UTS.

	Next, modify the 'fillscratch' entry in the makefile  so  that
    the invocations of CC include  a  '+xfile'	where  'file'  is  the
    size/alignment file above.	Here's how I did it for  UTS  (working
    from a VAX). I actually added a new target here:

	#   This makes port files for UTS
	#   UTS size/alignment file
	UTSDIR=/usr/src/c++/CC/UTS
	UAL=$(UTSDIR)/uts_size_align

	utsport:
		make sure the directories exist:
		if test ! -d uts/src; then mkdir uts/src; fi
		if test ! -d uts/mnch; then mkdir uts/mnch; fi
		if test ! -d uts/lib; then mkdir uts/lib; fi
		cd src; yacc gram.y
		cd uts/src; $(CC) +x$(UAL) -I$(UTSDIR) -I../../src -I../../incl \
			 -Fc -..c ../../src/*.c;
		cd uts/lib; $(CC) +x$(UAL) -I$(UTSDIR) -I../../lib/complex \
			 -I../../incl -Fc -..c ../../lib/new/*.c
		cd uts/lib; $(CC) +x$(UAL) -I$(UTSDIR) -I../../lib/complex \
			 -I../../incl -Fc -..c ../../lib/static/*.c
		rm uts/lib/munch..c
	#Dont need a real munch here:
		echo "main(){ exit(0); }" >uts/mnch/munch..c

	in the above segment of makefile, UTSDIR is the location of  a
    directory containing
	(i) The size_alignment file (which  is	defined  on  the  next
	    line)
	(ii) /usr/include/stdio.h and  /usr/include/ctype.h  from  the
	    target machine. It is VITAL that these be included instead
	    of the versions  of  stdio.h  and  ctype.h	in  the  incl/
	    directory.

	Make a	directory  'uts'  and  invoke  'make  utsport'.   When
    finished, uts/...  will contain  C	code  suitable	for  compiling
    under UTS.

	At this point, move the directory tree 'uts/...' from the host
    machine to the target.  Move  it  into  'scratch/...'  instead  of
    'uts/...' on  the  target,	and  proceed  with  the  bootstrapping
    process.

	IMPORTANT NOTE: the generated cfront  on  the  target  machine
    will    STILL    require	you    to    explicitly    use	   the
    '+xsize_alignment_file' for the target because, despite  the  fact
    that it was itself compiled correctly, the default size/alignments
    built in are those for a vax.  Two ways to work around this:

	(i) Modify the 'CC' script to ALWAYS use +x (putting the  file
	    in some  publicly  accessible  place,  probably  the  same
	    directory as CC itself).

	(ii) Modify the  file  'src/size.h'  to  contain  the  correct
	    size/alignments for your  target,  then  recompile	cfront
	    from the C++ source (again, using  the  +x	option).   The
	    cfront which  is  generated  will  now  have  the  correct
	    size/alignments   built   in.    It   is   also   a   good
	    confidence-building measure  for  cfront  to  be  able  to
	    successfully recompile itself on the target machine.  This
	    is my preferred solution.

	The include files installed in /usr/include/CC	(or  wherever)
    must be correct for the target. This could require	a  substantial
    amount of editing. 'incl/ctype.h' should  be  replaced  with  that
    from the target system's /usr/include. 'incl/stdio.h' should  also
    be replaced; however, you must add the correct function prototypes
    for your  system  to  stdio.h,  or	cfront	cannot	be  recompiled
    successfully.   The  problem  is  that  most  stdio.h  files  have
    declarations of the form

	extern int setbuf();

	unfortunately, C++ will interpret this	as  'setbuf  takes  NO
    arguments'.  When it then encounters  an  actual  call  to	setbuf
    (containing 2  arguments),	an  error  occurs.  Since  such  calls
    appear in the source to cfront itself, it cannot  be  successfully
    recompiled without adding the function prototypes to CC's stdio.h.

    C) Compiling the library libC.a (in lib/*/*)

	When compiling the full libC.a, you must change  'incl/math.h'
    (which  should  become  '/usr/include/CC/math.h')  to  include   a
    correct  definition  of  'MAXFLOAT'  for  your  system.   Look  in
    '/usr/include/math.h' for  MAXFLOAT  or  HUGE  (probably  labelled
    appropriately). There are other conditional  definitions  of  this
    nature in the CC include files, but  they  don't  seem  to	affect
    compiling cfront and libC.

	I found that for some reason (probably a shell or  make  bug),
    the following changes had to be made in  lib/mk/makefile  for  the
    Suns:

    OLD:
	OFILES	=	$(O_COMPLEX) $(O_GENERIC) $(O_NEW) \
			$(O_STATIC) $(O_STREAM) $(O_TASK)

    NEW:
	OFILES	=	$(O_COMPLEX) $(O_GENERIC) $(O_NEW) \
			$(O_STATIC) $(O_STREAM)

    OLD:
	libC.a: $(O_COMPLEX) $(O_GENERIC) $(O_NEW) $(O_STATIC) $(O_STREAM) Task

    NEW:
	libC.a: $(O_COMPLEX) $(O_GENERIC) $(O_NEW) $(O_STATIC) $(O_STREAM)

	The problem was that the shell code  executed  in  the	'Task'
    target was failing for some reason, and causing make to die. Since
    the task library is not supported on Suns anyway, there is no loss
    from doing this.

    D) Testing

	Getting cfront to recompile itself is certainly a  good  test.

    The only other test I have come up with is this progam:

	#include <stream.h>
	main() {
	    cout << "Hello, world\n";
	}

	What makes this worth  doing  is  that	'cout'	has  a	static
    constructor; thus, if the 'munch' program does not work  properly,
    said constructor will not be initialized and when the  program  is
    run   you	will   probably   get	a   core   dump    (dies    in
    __ostream__lshiftFPC__) instead of 'Hello, world'.

    E) From the author

	The following comments were sent to me	by  Bjarne  as	I  was
    trying to get C++ up ; there is some overlap with  the  above  but
    they may be more comprehensible than mine.

>   I will brifly explain the porting process here.  Cfront is a compiler front-end,
>   not a simple pre-processor, in particular it has to know about the target machine
>   in order to calculate sizeofs. What you get on the tape is a C version for a VAX
>   or a 3B. To run cfront on a different machine you must port, not merely re-compile.
>
>   When you port, the key step is to create a new set of C source files like the ones
>   you received for a VAX. This you do by compiling the C++ source files using
>
>	(1) header files <stdio.h> and <ctype.h> from the target machine (using
>	    the -I directive) so that the system dependencies are hanled correctly.
>	(2) a size/align file for the target machine (using the +x directive) so
>	    that cfront agrees with the target machine as to the sizes of objects.
>
>	    (here is the source of your problem with expr..c - the sizes has been
>	    calculated wrongly using VAX sizes on a SUN and the free store is
>	    messed up).
>
>	    Here is a size/align file for a Sun:

	[ Given above ]

>   Assuming you call it ``szal'' and put it in directory SUN (where I have also
>   assumed that stdio.h and ctype.h is stored) you can make a ..c file like this:
>
>   CC -F -ISUN +xSUN/szal main.c | sed /^#/d > main..c
>
>   Don't worry about SZ_TOP and AL_TOP, they are not really used.
>
>   With that done you can simply compile and install munch.c and the libraries on
>   the terget machine using the new cfront.
>
>   This is of course not as easy as porting a simple machine independent C program,
>   but not too bad for a compile port. Think of CC as a two pass compiler using a
>   particularly readable and portable intermediate form (seen this way cc is the
>   fabled ``machine independent assembler'' or ``universal intermediate form'' -
>   UNCOL).
>
>		- Bjarne

    Jon Leech	(jon@csvax.caltech.edu || ...seismo!cit-vax!jon)
    Caltech Computer Science Graphics Group
    __@/

olson@batcomputer.TN.CORNELL.EDU (Todd Olson) (03/24/86)

In article <952@megaron.UUCP> whm@megaron.UUCP writes:
>I just installed C++ on our 4.3bsd VAXs and it didn't go too smoothly.

Yes, indeed.  I've been thinking about posting a similar article about
the problems of bring C++ under bsd4.2 and asking for assistance.  I
have experienced every problem you have, and since I'm not too
experienced in bring things up I have been stumbling all over the place.

Maybe some of the wiser 4.2 types with interest in C++ could be pursuaded
to make available a better make file (maybe it could go on the
distribution tape)  (I guess I have been spoiled by all the fine work the
UW people did in making TeX available for bsd4.*)

Thanks for your note, it will help me.  If I ever get my C++ up
I'll post my experiences

Todd Olson

ARPA: olson@lasspvax  -- or --  olson%lasspvax.tn.cornell.edu@cu-arpa
UUCP: {ihnp4,allegra,...}!cornell!lasspvax!olson
US Mail: Dept Physics, Clark Hall, Cornell University,
	 Ithaca, New York 14853-2501
-- 
Todd Olson

ARPA: olson@lasspvax  -- or --  olson%lasspvax.tn.cornell.edu@cu-arpa
UUCP: {ihnp4,allegra,...}!cornell!lasspvax!olson
US Mail: Dept Physics, Clark Hall, Cornell University,
	 Ithaca, New York 14853-2501

mat@mtx5a.UUCP (m.terribile) (04/03/86)

>     WARNING: The following  is	a  LONG  (~440	lines)	message  about
> problems and experiences porting C++.  Hit  'n'  now  unless  you  are
> having problems getting the new release of C++ running.
. . .
>     B) Optimization
> 
> 	On UTS, the optimizer pass of the C compiler (/lib/c2)  core
>     dumps while trying to compile parts of the C++ library
>     (specifically lib/complex/io.c). Rather than try to figure out
>     why, I just removed the -O flag from 'lib/mk/makefile' and
>     'makefile'.  Bjarne says that many optimizers break on
>     automagically generated C code such as that produced by cfront.

I can understand why compilers might have difficulty.  On the other hand,
it is precisely on automagically generated code that optimization is
most needed, because such code is most likely to have extra copy and
conversion operations introduced by the crypto-automagicalator (eg. cfront :-)
Those of us who are in a postion to influence such things should push for
robust compilers and optimizers; Maytags, if you will, that can take lots of
use and come up for more.

> 	Getting cfront to recompile itself is certainly a  good  test.
> 
>     The only other test I have come up with is this progam:
> 
> 	#include <stream.h>
> 	main() {
> 	    cout << "Hello, world\n";
> 	}
> 
> 	What makes this worth  doing  is  that	'cout'	has  a	static
>     constructor; thus, if the 'munch' program does not work  properly,
>     said constructor will not be initialized and when the  program  is
>     run   you	will   probably   get	a   core   dump    (dies    in
>     __ostream__lshiftFPC__) instead of 'Hello, world'.

Ah, yes.  For those of you who have the ``patch'' version instead of the
``munch'' version, if this error occurs, check the symbols in the source
code for ``patch''.  You may find that your cc puts in more or fewer
underscores than patch expects.  There are two or three lines that need
to be changed, and the code is surprisingly simple.  I have the patch
version up here, and it seems to run fine.
-- 

	from Mole End			Mark Terribile
		(scrape .. dig )	mtx5b!mat
					(Please mail to mtx5b!mat, NOT mtx5a!
						mat, or to mtx5a!mtx5b!mat)
    ,..      .,,       ,,,   ..,***_*.