ksherlock / mpw

Macintosh Programmer's Workshop (mpw) compatibility layer
238 stars 21 forks source link

pathnames.rl wrong handling of paths to other volumes #59

Open ryandesign opened 1 year ago

ryandesign commented 1 year ago

toolbox/pathnames.rl has this comment illustrating the conversions it performs:

    /*
     * To Mac:
     * file                -> file
     * :directory:file     -> directory/file
     * volume:directory    -> /volume/directory
     * :                   -> ./
     * ::                  -> ../
     * :::                 -> ../../
     *
     * To Unix:
     * file                -> file
     * directory/file      -> :directory:file
     * /volume/file        -> volume:file
     *
     */

First of all, the "To Mac" and "To Unix" headings are backwards, aren't they?

And for volumes, at least when "Unix" means "macOS", the conversion should be:

Other unices mount their volumes elsewhere.

I'm trying to use MWC68K & MWCPPC to compile a project, and in order to write a Makefile that allows out-of-source builds, some include paths and file paths have had to become absolute, so they're rather long. MWC68K & MWCPPC appear to have their own code to check whether the given paths are valid, and based on classic Mac OS rules, they're not. MWC68K & MWCPPC don't know that the directory separator in my world is "/" so it thinks I've asked it to operate on a file whose name is longer than 31 characters:

% pwd
/Volumes/Shared/long-pathname-test
% mpw MWC68K test.c
% rm test.c.o
% mpw MWC68K $PWD/test.c
### MWC68K Usage Error:
# some component of pathname is too long;
# files/directories <= 31 and full pathname <= 255;
# '/Volumes/Shared/long-pathname-test/test.c' not accepted
# errors caused tool to abort

I don't suppose there's any way for mpw to know which arguments I've passed are supposed to represent filesystem paths so that it could convert those from Unix to Mac format for me, so I've tried converting them myself. The problem then is that my files are not on the main volume but on a separate volume called "Shared". The Unix path to the Shared volume on macOS is "/Volumes/Shared". The Mac OS path to that volume is "Shared:". We can confirm that using AppleScript:

% osascript -e 'POSIX file "/Volumes/Shared" as text' 
Shared:

Here's therefore what I've tried and the result:

% mpw MWC68K $(osascript -e "POSIX file \"$PWD/test.c\" as text")       
### MWC68K OS Error:
# can't resolve file path for 'Shared:long-pathname-test:test.c'
# OS error -41 (Error message file not available)
# errors caused tool to abort

What does work, but shouldn't, is:

% mpw MWC68K Volumes:$(osascript -e "POSIX file \"$PWD/test.c\" as text")
ksherlock commented 1 year ago

Pathname conversion also handles mpw-style environmental variable substitution so you could do something like:

mpw -DPWD="$PWD" mwc68k -v {PWD}:test.c

ryandesign commented 1 year ago

Thanks, that's working. I hadn't considered that it could be used that way. I guess I thought it would work like today's shells, where the shell (or in this case mpw) would expand the variables first, then pass the expanded paths to the compiler, which wouldn't have fixed this problem.


Using $PWD was just an example to show what happens with long paths. The real use case is a GNU Makefile something like this:

SRC_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
INCLUDE_DIR := $(SRC_DIR)/../include
MPW ?= mpw
MPWFLAGS ?=
CC_68K ?= $(MPW) $(MPWFLAGS) MWC68K
CC_PPC ?= $(MPW) $(MPWFLAGS) MWCPPC
CFLAGS := -opt all $(CFLAGS)
CFLAGS_68K := $(CFLAGS) $(CFLAGS_68K)
CFLAGS_PPC := $(CFLAGS) $(CFLAGS_PPC)
CPPFLAGS := -i $(INCLUDE_DIR) $(CPPFLAGS)
CPPFLAGS_68K := $(CPPFLAGS) $(CPPFLAGS_68K)
CPPFLAGS_PPC := $(CPPFLAGS) $(CPPFLAGS_PPC)

%.68k.o : $(SRC_DIR)/%.c
    $(CC_68K) $(CFLAGS_68K) $(CPPFLAGS_68K) $< -o $@

%.ppc.o : $(SRC_DIR)/%.c
    $(CC_PPC) $(CFLAGS_PPC) $(CPPFLAGS_PPC) $< -o $@

The dependencies are specified as $(SRC_DIR)/%.c rather than just %.c to accommodate out-of-source building, i.e.:

mkdir build
cd build
make -f ../Makefile

Maybe there is a better way to accomplish this? I always struggle with Makefiles when I try to do something even slightly advanced. This technique was the first one I found.

Because the dependencies are written as $(SRC_DIR)/%.c, $< expands to the full path to the file, which MWC68K/MWCPPC then complains about because it thinks it's a too-long filename.

I was playing around with various Makefile functions to transform the Unix path to a Mac path before passing it to MWC68K/MWCPPC, such as:

unix2mac = $(shell osascript -e 'on run argv' -e 'POSIX file (item 1 of argv) as text' -e 'end run' "$(1)")
    $(CC_PPC) $(CFLAGS_PPC) $(CPPFLAGS_PPC) $(call unix2mac,$<) -o $@

which is when I noticed the discrepancy between how Apple represents Mac paths and how mpw is doing it. Upon reflection, maybe it's ok that mpw does it differently; it just needs to be good enough for mpw. And if the user needs to enter such paths, then the user needs to understand the required syntax.

I had wanted to use AppleScript to do the conversion since there are multiple steps to a successful conversion, but if mpw uses a simplified method then writing some sed statements to transform paths is probably feasible, if it ends up being needed.

With your suggestion, I was able to rewrite my Makefile and make it work:

SRC_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
INCLUDE_DIR := $(SRC_DIR)/../include
MPW ?= mpw
MPWFLAGS := -Dsrc=$(SRC_DIR) -Dinc=$(INCLUDE_DIR) $(MPWFLAGS)
CC_68K ?= $(MPW) $(MPWFLAGS) MWC68K
CC_PPC ?= $(MPW) $(MPWFLAGS) MWCPPC
CFLAGS := -opt all $(CFLAGS)
CFLAGS_68K := $(CFLAGS) $(CFLAGS_68K)
CFLAGS_PPC := $(CFLAGS) $(CFLAGS_PPC)
CPPFLAGS := -i {inc} $(CPPFLAGS)
CPPFLAGS_68K := $(CPPFLAGS) $(CPPFLAGS_68K)
CPPFLAGS_PPC := $(CPPFLAGS) $(CPPFLAGS_PPC)

%.68k.o : $(SRC_DIR)/%.c
    $(CC_68K) $(CFLAGS_68K) $(CPPFLAGS_68K) {src}:$(notdir $<) -o $@

%.ppc.o : $(SRC_DIR)/%.c
    $(CC_PPC) $(CFLAGS_PPC) $(CPPFLAGS_PPC) {src}:$(notdir $<) -o $@