I spent the last couple of evenings trying to build the gEDA tools on my MacBook Pro with Mac OS X 10.7 Lion. The biggest resistance came from GNU Guile.
To create printed circuit boards, I’ve been using the gEDA tools for many years. They contain the gschem application for drawing schematic diagrams, the PCB application for creating PCBs and many other useful tools. I used to build these tools and all dependencies from source because I have other things like the AVR cross compiler and more which I want to keep separate from each other. So, the gEDA tools go into /usr/local/geda, together with all dependencies.
Yesterday, I managed to build PCB and gerbv successfully, and today I decided to dig deeper into the segmentation fault that I get when compiling GNU Guile, the GNU Ubiquitous Language for Extentions. The Guile package is a prerequisite for gschem. You can see in the screenshot above the segmentation fault that I got. I tried with version 1.8.8 (and then 1.8.7 after finding a hint on the web). They both failed with “Segmentation fault: 11”.
The most recent version 2.0.2 somehow entered an infinite loop or so after displaying the message “GUILEC ice-9/psyntax-pp.go” in the ‘make’ phase, so I decided to stick with 1.8.7 and try to make it work.
Some info about my environment:
gcc --version on my machine returns i686-apple-darwin11-llvm-gcc-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.1.00) Copyright (C) 2007 Free Software Foundation, Inc. ....
gc is gc-7.2alpha6.
Today I attached GDB and captured a stack trace:
The problem arises in gc-mark.c on line 438. There is a for loop at that position:
/* Mark a region conservatively */ void scm_mark_locations (SCM_STACKITEM x[], unsigned long n) { unsigned long m; for (m = 0; m < n; ++m) { SCM obj = * (SCM *) &x[m]; // THIS IS LINE 438 long int segment = scm_i_find_heap_segment_containing_object (obj); if (segment >= 0) scm_gc_mark (obj); } }
I figured out that the value of the parameter ‘n’ is far too large (18446744073709551543) and decided to have a look at the caller, line 1408 in threads.c:
void scm_threads_mark_stacks (void) { scm_i_thread *t; for (t = all_threads; t; t = t->next_thread) { /* Check that thread has indeed been suspended. */ assert (t->top); scm_gc_mark (t->handle); #if SCM_STACK_GROWS_UP scm_mark_locations (t->base, t->top - t->base); #else scm_mark_locations (t->top, t->base - t->top); #endif scm_mark_locations ((void *) &t->regs, ((size_t) sizeof(t->regs) / sizeof (SCM_STACKITEM))); } SCM_MARK_BACKING_STORE (); }
So, the difference ‘t->top - t->base’ was ways too large. The code in the #else would have given a much more reasonable difference, about 50 or so. It seemed that the SCM_STACK_GROWS_UP was defined while it shouldn’t have been.
The configure script is responsible for setting SCM_STACK_GROWS_UP via another variable, SCM_I_GSC_STACK_GROWS_UP, which it determines in a method called find_stack_direction in the configure script:
int find_stack_direction () { static char *addr = 0; auto char dummy; if (addr == 0) { addr = &dummy; return find_stack_direction (); } else return (&dummy > addr) ? 1 : -1; }
I put a few printf statements there and found out that the address (addr) changed from 0x7FFF63FBFAF6 in the first call to 0x7FFF63FBFAF6 in the second, recursive call:
So, the return value of the method was 1, indicating a stack growth towards higher addresses.
I then decided to experiment with the method and see what happens if I put more variables on the stack:
int find_stack_direction () { static char *addr = 0; auto char dummy0; auto char dummy; auto char dummy2; printf("************ -> addr = %lx\n", (unsigned long)addr); if (addr == 0) { addr = &dummy; printf("************ -> now addr = %lx\n", (unsigned long)addr); return find_stack_direction (); } else { int x = (&dummy > addr) ? 1 : -1; printf("************ -> &dummy = %lx, addr = %lx, x = %d v=%c/w=%c\n", (unsigned long)&dummy, (unsigned long)addr, x, dummy0, dummy2); return x; } }
Now, the result looked much better:
So, it seems like the above approach to “calculate” the stack direction may not be the best idea...
(After figuring this out, I had a look at the corresponding method in version 2.0.2 of guile. Somebody has fixed the find_stack_direction:
int find_stack_direction (int *addr, int depth) { int dir, dummy = 0; if (! addr) addr = &dummy; *addr = addr < &dummy ? 1 : addr == &dummy ? 0 : -1; dir = depth ? find_stack_direction (addr, depth - 1) : 0; return dir + dummy; }
The new version correctly determines that the stack grows down on my machine.)
At least, I could compile the GNU Guile package and afterwards geda-gaf with this “hotfix”.
There remains an issue with displaying fonts in gschem, but I’ll have a look at this on another evening.
I also plan to create a short step-by-step guide on how to successfully build the gEDA tools on Mac OS X 10.7 Lion.