From: lele@itnsg1.cineca.it (Lele Gaifax)
Subject: Re: Building Emacs on a NeXT
Organization: Laboratorio di Fisica Computazionale, INFM. Trento Italia
Date: Thu, 13 Aug 1992 09:29:02 GMT

Here is the patches I used to compile 18.58 on my NeXTstation with NeXTstep 2.2.
I extracted them from an emacs-18.57.tar.Z available on several NeXT archives.
Apply it to a fresh 18.58 distribution, modify src/config.h to use s-mach.h and
m-NeXT.h, then do a make... That's it.
I did not write a single bit of this code, I just produced it diff-ing the
18.57 sources against 18.58....
bye, lele.

--- src/emacs.c.orig	Sat Jun 15 04:52:00 1991
+++ src/emacs.c	Sat Jun 15 04:56:55 1991
@@ -178,6 +178,9 @@
 #endif /* LINK_CRTL_SHARE */
 #endif /* VMS */
 
+#ifdef NeXT
+int malloc_cookie;
+#endif /* NeXT */
 /* ARGSUSED */
 main (argc, argv, envp)
      int argc;
@@ -187,6 +190,13 @@
   int skip_args = 0;
   extern int errno;
   extern void malloc_warning ();
+
+#ifdef NeXT
+   /* this helps out unexNeXT.c */
+   if (initialized)
+     if (malloc_jumpstart(malloc_cookie) != 0)
+       printf("malloc jumpstart failed!\n");
+#endif /* NeXT */
 
 /* Map in shared memory, if we are using that.  */
 #ifdef HAVE_SHM
--- src/fns.c.orig	Sat Jun 15 04:52:03 1991
+++ src/fns.c	Sat Jun 15 04:53:01 1991
@@ -1204,8 +1204,13 @@
       nl[0].n_un.n_name = LDAV_SYMBOL;
       nl[1].n_un.n_name = 0;
 #else /* not convex */
+#ifdef NEXT_KERNEL_FILE
+      nl[0].n_un.n_name = LDAV_SYMBOL;
+      nl[1].n_un.n_name = 0;
+#else
       nl[0].n_name = LDAV_SYMBOL;
       nl[1].n_name = 0;
+#endif /* not NEXT_KERNEL_FILE */
 #endif /* not convex */
 #endif /* NLIST_STRUCT */
 
@@ -1217,7 +1222,11 @@
 	    nl[0].n_value &= 0x7fffffff;
 	}
 #else
+#ifdef NEXT_KERNEL_FILE
+      nlist (NEXT_KERNEL_FILE, nl);
+#else
       nlist (KERNEL_FILE, nl);
+#endif
 #endif /* IRIS */
 
 #ifdef FIXUP_KERNEL_SYMBOL_ADDR
--- src/sysdep.c.orig	Sat Jun 15 04:52:04 1991
+++ src/sysdep.c	Sat Jun 15 04:53:03 1991
@@ -1472,8 +1472,12 @@
   extern csrt();
   return ((char *) csrt);
 #else /* not GOULD */
+#ifdef NeXT
+  return ((char *)0); /* wrong: but nobody uses it anyway */
+#else
   extern int _start ();
   return ((char *) _start);
+#endif /* NeXT */
 #endif /* GOULD */
 #endif /* TEXT_START */
 }
@@ -1531,7 +1535,13 @@
 #ifdef TEXT_END
   return ((char *) TEXT_END);
 #else
+#ifdef __NeXT__
+  static int etext;
+
+  etext = get_etext();
+#else
   extern int etext;
+#endif
   return ((char *) &etext);
 #endif
 }
@@ -1547,7 +1557,13 @@
 #ifdef DATA_END
   return ((char *) DATA_END);
 #else
+#ifdef __NeXT__
+  static int edata;
+
+  edata = get_edata();
+#else
   extern int edata;
+#endif
   return ((char *) &edata);
 #endif
 }
--- src/x11term.c.orig	Sat Jun 15 04:52:02 1991
+++ src/x11term.c	Sat Jun 15 04:53:05 1991
@@ -273,7 +273,9 @@
 
 static void x_init_1 ();
 
+#ifndef rindex
 char *rindex();
+#endif /* rindex */
 
 /* HLmode -- Changes the GX function for output strings.  Could be used to
  * change font.  Check an XText library function call.
--- /dev/null	Wed Jul 15 18:14:58 1992
+++ src/s-mach.h	Sat Jun 15 04:58:01 1991
@@ -0,0 +1,28 @@
+/* Definitions file for GNU Emacs running on bsd 4.3
+   Copyright (C) 1985, 1986 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY.  No author or distributor
+accepts responsibility to anyone for the consequences of using it
+or for whether it serves any particular purpose or works at all,
+unless he says so in writing.  Refer to the GNU Emacs General Public
+License for full details.
+
+Everyone is granted permission to copy, modify and redistribute
+GNU Emacs, but only under the conditions described in the
+GNU Emacs General Public License.   A copy of this license is
+supposed to have been given to you along with GNU Emacs so you
+can know your rights and responsibilities.  It should be in a
+file named COPYING.  Among other things, the copyright notice
+and this notice must be preserved on all copies.  */
+
+
+#include "s-bsd4-3.h"
+#define NEXT_KERNEL_FILE "/mach"
+/* #define NEXT_KERNEL_FILE "/vmunix" */
+#undef KERNEL_FILE
+
+#define LD_SWITCH_SYSTEM -X -noseglinkedit
+
--- /dev/null	Wed Jul 15 18:14:58 1992
+++ src/m-NeXT.h	Sat Jun 15 04:52:36 1991
@@ -0,0 +1,98 @@
+/* Configuration file for the NeXT machine. */
+/*    Copyright (C) 1985, 1986 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY.  No author or distributor
+accepts responsibility to anyone for the consequences of using it
+or for whether it serves any particular purpose or works at all,
+unless he says so in writing.  Refer to the GNU Emacs General Public
+License for full details.
+
+Everyone is granted permission to copy, modify and redistribute
+GNU Emacs, but only under the conditions described in the
+GNU Emacs General Public License.   A copy of this license is
+supposed to have been given to you along with GNU Emacs so you
+can know your rights and responsibilities.  It should be in a
+file named COPYING.  Among other things, the copyright notice
+and this notice must be preserved on all copies.  */
+
+
+
+
+
+
+
+/* The following three symbols give information on
+ the size of various data types.  */
+
+#define SHORTBITS 16		/* Number of bits in a short */
+
+#define INTBITS 32		/* Number of bits in an int */
+
+#define LONGBITS 32		/* Number of bits in a long */
+
+/* 68000 has lowest-numbered byte as most significant */
+
+#define BIG_ENDIAN
+
+/* Define how to take a char and sign-extend into an int.
+   On machines where char is signed, this is a no-op.  */
+
+#define SIGN_EXTEND_CHAR(c) (c)
+
+/* Say this machine is a 68000 */
+
+#ifndef m68000
+#define m68000
+#endif
+
+/* Use type int rather than a union, to represent Lisp_Object */
+
+#define NO_UNION_TYPE
+
+/* XINT must explicitly sign-extend */
+
+#define EXPLICIT_SIGN_EXTEND
+
+#define LIB_STANDARD -lsys_s
+
+/* Data type of load average, as read out of kmem.  */
+
+#define LOAD_AVE_TYPE long
+
+/* Convert that into an integer that is 100 for a load average of 1.0  */
+
+#define environ _environ
+
+#define NO_REMAP
+#define UNEXEC unexNeXT.o
+
+#ifndef FSCALE
+#define FSCALE 256
+#endif
+#define LOAD_AVE_CVT(x) (int) (((double) (x)) * 100.0 / FSCALE)
+
+/* Say that the text segment of a.out includes the header;
+   the header actually occupies the first few bytes of the text segment
+   and is counted in hdr.a_text.  */
+
+#define A_TEXT_OFFSET(HDR) sizeof (HDR)
+
+/* #define _setjmp setjmp */
+/* #define _longjmp longjmp */
+
+/* Use dk.h, not dkstat.h, in loadst.c.  */
+
+#define DK_HEADER_FILE
+/* Mask for address bits within a memory segment */
+
+#define SEGSIZ 0x20000
+#define SEGMENT_MASK (SEGSIZ - 1)
+
+#define HAVE_ALLOCA
+
+#define SYSTEM_MALLOC
+
+#define HAVE_UNIX_DOMAIN
--- /dev/null	Wed Jul 15 18:14:58 1992
+++ src/unexNeXT.c	Sat Jun 15 04:52:35 1991
@@ -0,0 +1,422 @@
+/*
+ * unexec for the NeXT Mach environment.
+ *
+ * Bradley Taylor (btaylor@NeXT.COM) 
+ * February 28, 1990
+ */
+#ifdef NeXT
+
+#undef __STRICT_BSD__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <mach.h>
+#include <sys/loader.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <libc.h>
+
+
+extern struct section *getsectbyname(char *, char *);
+
+/*
+ * Kludge: we don't expect any program data beyond VM_HIGHDATA
+ * What is really needed is a way to find out from malloc() which
+ * pages it vm_allocated and write only those out into the data segment.
+ *
+ * This kludge may break when we stop using fixed virtual address
+ * shared libraries. Actually, emacs will probably continue working, but be 
+ * much larger on disk than it needs to be (because non-malloced data will
+ * be in the file).
+ */
+static const unsigned VM_HIGHDATA = 0x2000000;
+
+typedef struct region_t {
+	vm_address_t address;
+	vm_size_t size;
+	vm_prot_t protection;
+	vm_prot_t max_protection;
+	vm_inherit_t inheritance;
+	boolean_t shared;
+	port_t object_name;
+	vm_offset_t offset;
+} region_t;
+
+
+static void
+grow(
+     struct load_command ***the_commands,
+     unsigned *the_commands_len
+     )
+{
+	if (*the_commands == NULL) {
+		*the_commands_len = 1;
+		*the_commands = malloc(sizeof(*the_commands));
+	} else {
+		(*the_commands_len)++;
+		*the_commands = realloc(*the_commands, 
+					(*the_commands_len *
+					 sizeof(**the_commands)));
+	}
+}
+
+
+static void
+save_command(
+	     struct load_command *command,
+	     struct load_command ***the_commands,
+	     unsigned *the_commands_len
+	     )
+{
+	struct load_command **tmp;
+
+	grow(the_commands, the_commands_len);
+	tmp = &(*the_commands)[*the_commands_len - 1];
+	*tmp = malloc(command->cmdsize);
+	bcopy(command, *tmp, command->cmdsize);
+}
+
+static void
+fatal_unexec(char *format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
+	fprintf(stderr, "unexec: ");
+	vfprintf(stderr, format, ap);
+	fprintf(stderr, "\n");
+	va_end(ap);
+}
+
+static int
+read_macho(
+	   int fd,
+	   struct mach_header *the_header,
+	   struct load_command ***the_commands,
+	   unsigned *the_commands_len
+	   )
+{
+	struct load_command command;
+	struct load_command *buf;
+	int i;
+	int size;
+
+	if (read(fd, the_header, sizeof(*the_header)) != sizeof(*the_header)) {
+		fatal_unexec("cannot read macho header");
+		return (0);
+	}
+	for (i = 0; i < the_header->ncmds; i++) {
+		if (read(fd, &command, sizeof(struct load_command)) != 
+		    sizeof(struct load_command)) {
+		  	fatal_unexec("cannot read macho load command header");
+			return (0);
+		}
+		size = command.cmdsize - sizeof(struct load_command);
+		if (size < 0) {
+		  	fatal_unexec("bogus load command size");
+			return (0);
+		}
+		buf = malloc(command.cmdsize);
+		buf->cmd = command.cmd;
+		buf->cmdsize = command.cmdsize;
+		if (read(fd, ((char *)buf + 
+			      sizeof(struct load_command)), 
+			 size) != size) {
+		  	fatal_unexec("cannot read load command data");
+			return (0);
+		}
+		save_command(buf, the_commands, the_commands_len);
+	}
+	return (1);
+}
+
+static int
+filldatagap(
+	    vm_address_t start_address,
+	    vm_size_t *size,
+	    vm_address_t end_address
+	    )
+{
+	vm_address_t address;
+	vm_size_t gapsize;
+
+	address = (start_address + *size);
+	gapsize = end_address - address;
+	*size += gapsize;
+	if (vm_allocate(task_self(), &address, gapsize,
+			FALSE) != KERN_SUCCESS) {
+		fatal_unexec("cannot vm_allocate");
+	        return (0);
+	}
+	return (1);
+}
+
+static int
+get_data_region(
+		vm_address_t *address,
+		vm_size_t *size
+		)
+{
+	region_t region;
+	kern_return_t ret;
+	struct section *sect;
+
+	sect = getsectbyname(SEG_DATA, SECT_DATA);
+	region.address = 0;
+	*address = 0;
+	for (;;) {
+		ret = vm_region(task_self(), 
+				&region.address, 
+				&region.size, 
+				&region.protection, 
+				&region.max_protection, 
+				&region.inheritance,
+				&region.shared, 
+				&region.object_name, 
+				&region.offset);
+		if (ret != KERN_SUCCESS || region.address >= VM_HIGHDATA) {
+			break;
+		}
+		if (*address != 0) {
+			if (region.address > *address + *size) {
+				if (!filldatagap(*address, size, 
+						 region.address)) {
+					return (0);
+				}
+			} 
+			*size += region.size;
+		} else {
+			if (region.address == sect->addr) {
+				*address = region.address;
+				*size = region.size;
+			} 
+		}
+		region.address += region.size;
+	}
+	return (1);
+}
+
+static char *
+my_malloc(
+	  vm_size_t size
+	  )
+{
+	vm_address_t address;
+
+	if (vm_allocate(task_self(), &address, size, TRUE) != KERN_SUCCESS) {
+		return (NULL);
+	}
+	return ((char *)address);
+}
+
+static void
+my_free(
+	char *buf,
+	vm_size_t size
+	)
+{
+	vm_deallocate(task_self(), (vm_address_t)buf, size);
+}
+
+static int
+unexec_doit(
+	    int infd,
+	    int outfd
+	    )
+{
+	int i;
+	struct load_command **the_commands = NULL;
+	unsigned the_commands_len;
+	struct mach_header the_header;
+	int fgrowth;
+	int fdatastart;
+	int fdatasize;
+	int size;
+	struct stat st;
+	char *buf;
+	vm_address_t data_address;
+	vm_size_t data_size;
+
+	struct segment_command *segment;
+
+	if (!read_macho(infd, &the_header, &the_commands, &the_commands_len)) {
+		return (0);
+	}
+
+
+	{
+	  extern int malloc_cookie;
+	  malloc_cookie = malloc_freezedry();
+	}
+	if (!get_data_region(&data_address, &data_size)) {
+		return (0);
+	}
+
+
+	/*
+	 * DO NOT USE MALLOC IN THIS SECTION
+	 */
+	{
+		/*
+		 * Fix offsets
+		 */
+		for (i = 0; i < the_commands_len; i++) {
+			switch (the_commands[i]->cmd) {
+			case LC_SEGMENT:
+				segment = ((struct segment_command *)
+					   the_commands[i]);
+				if (strcmp(segment->segname, SEG_DATA) == 0) {
+					fdatastart = segment->fileoff;
+					fdatasize = segment->filesize;
+					fgrowth = (data_size - 
+						   segment->filesize);
+					segment->vmsize = data_size;
+					segment->filesize = data_size;
+				}
+				break;
+			case LC_SYMTAB:
+				((struct symtab_command *)
+				 the_commands[i])->symoff += fgrowth;
+				((struct symtab_command *)
+				 the_commands[i])->stroff += fgrowth;
+				break;
+			case LC_SYMSEG:
+				((struct symseg_command *)
+				 the_commands[i])->offset += fgrowth;
+				break;
+			default:
+				break;
+			}
+		}
+		
+		/*
+		 * Write header
+		 */
+		if (write(outfd, &the_header, 
+			  sizeof(the_header)) != sizeof(the_header)) {
+			fatal_unexec("cannot write output file");
+			return (0);
+		}
+		
+		/*
+		 * Write commands
+		 */
+		for (i = 0; i < the_commands_len; i++) {
+			if (write(outfd, the_commands[i], 
+				  the_commands[i]->cmdsize) != 
+			    the_commands[i]->cmdsize) {
+			  	fatal_unexec("cannot write output file");
+				return (0);
+			}
+		}
+		
+		/*
+		 * Write original text
+		 */
+		if (lseek(infd, the_header.sizeofcmds + sizeof(the_header), 
+			  L_SET) < 0) {
+		  	fatal_unexec("cannot seek input file");
+			return (0);
+		}
+		size = fdatastart - (sizeof(the_header) + 
+				     the_header.sizeofcmds);
+		buf = my_malloc(size);
+		if (read(infd, buf, size) != size) {
+			my_free(buf, size);
+		  	fatal_unexec("cannot read input file");
+		}
+		if (write(outfd, buf, size) != size) {
+			my_free(buf, size);
+			fatal_unexec("cannot write output file");
+			return (0);
+		}
+		my_free(buf, size);
+		
+		
+		/*
+		 * Write new data
+		 */
+		if (write(outfd, (char *)data_address, 
+			  data_size) != data_size) {
+			fatal_unexec("cannot write output file");
+			return (0);
+		}
+		
+	}
+
+	/*
+	 * OKAY TO USE MALLOC NOW
+	 */
+
+	/*
+	 * Write rest of file
+	 */
+	fstat(infd, &st);
+	if (lseek(infd, fdatasize, L_INCR) < 0) {
+		fatal_unexec("cannot seek input file");
+		return (0);
+	}
+	size = st.st_size - lseek(infd, 0, L_INCR);
+
+	buf = malloc(size);
+	if (read(infd, buf, size) != size) {
+		free(buf);
+		fatal_unexec("cannot read input file");
+		return (0);
+	}
+	if (write(outfd, buf, size) != size) {
+		free(buf);
+		fatal_unexec("cannot write output file");
+		return (0);
+	}
+	free(buf);
+	return (1);
+}
+
+void
+unexec(
+       char *outfile,
+       char *infile
+       )
+{
+	int infd;
+	int outfd;
+	char tmpbuf[L_tmpnam];
+	char *tmpfile;
+
+	infd = open(infile, O_RDONLY, 0);
+	if (infd < 0) {
+	  	fatal_unexec("cannot open input file `%s'", infile);
+		exit(1);
+	}
+	
+	tmpnam(tmpbuf);
+	tmpfile = rindex(tmpbuf, '/');
+	if (tmpfile == NULL) {
+		tmpfile = tmpbuf;
+	} else {
+		tmpfile++;
+	}
+	outfd = open(tmpfile, O_WRONLY|O_TRUNC|O_CREAT, 0755);
+	if (outfd < 0) {
+		close(infd);
+		fatal_unexec("cannot open tmp file `%s'", tmpfile);
+		exit(1);
+	}
+	if (!unexec_doit(infd, outfd)) {
+		close(infd);
+		close(outfd);
+		unlink(tmpfile);
+		exit(1);
+	}
+	close(infd);
+	close(outfd);
+	if (rename(tmpfile, outfile) < 0) {
+		unlink(tmpfile);
+		fatal_unexec("cannot rename `%s' to `%s'", tmpfile, outfile);
+		exit(1);
+	}
+}
+#endif
+
-- 
Lele Gaifax - lele@itnsg1.cineca.it
Sicuramente i cattivi hanno scoperto qualche cosa che i buoni ignorano.
						- Woody Allen