diff mbox

[ada] : Last fix for PR ada/47163 on windows native hosts

Message ID BANLkTinLiuCVOP9LLNVQ+w5tX2c0MWw9Nw@mail.gmail.com
State New
Headers show

Commit Message

Kai Tietz April 4, 2011, 7:47 a.m. UTC
Hello,

as described in PR, there is a failure to copy adainclude/adalib
libraries in MSYS.
This is caused by LN_S set to cp -p for MSYS. This option for cp is
not suitable to copy folder to folder in MSYS, and the additional
option -r is necessary.

ChangeLog

2011-04-04  Kai Tietz

        PR ada/47163
        * gcc-interface/Makefile.in (LN_S): Use additional -r option
for cp in MSYS.

Ok for apply?

Regards,
Kai

Comments

Arnaud Charlet April 5, 2011, 8:03 a.m. UTC | #1
> as described in PR, there is a failure to copy adainclude/adalib
> libraries in MSYS.

The PR does not give any details as to what exact error message you are
getting, at which step, and what Makefile rule/line is causing this behavior.

I'm surprised by LN_S is used to link directories,this looks unexpected to
me at first sight, and first needs to be investigateed/clarified before
deciding on a proper fix.

Arno
Kai Tietz April 5, 2011, 8:43 a.m. UTC | #2
2011/4/5 Arnaud Charlet <charlet@adacore.com>:
>> as described in PR, there is a failure to copy adainclude/adalib
>> libraries in MSYS.
>
> The PR does not give any details as to what exact error message you are
> getting, at which step, and what Makefile rule/line is causing this behavior.
>
> I'm surprised by LN_S is used to link directories,this looks unexpected to
> me at first sight, and first needs to be investigateed/clarified before
> deciding on a proper fix.
>
> Arno
>

Hmm, AFAICS is in Mafile.in the following line present:

# Copy target independent sources
        $(foreach f,$(ADA_INCLUDE_SRCS) $(LIBGNAT_SRCS), \
          $(LN_S) $(fsrcpfx)ada/$(f) $(RTSDIR) ;) true

which seems to me the cause for this patch.

Kai
Arnaud Charlet April 5, 2011, 8:51 a.m. UTC | #3
> Hmm, AFAICS is in Mafile.in the following line present:
> 
> # Copy target independent sources
>         $(foreach f,$(ADA_INCLUDE_SRCS) $(LIBGNAT_SRCS), \
>           $(LN_S) $(fsrcpfx)ada/$(f) $(RTSDIR) ;) true
> 
> which seems to me the cause for this patch.

The above loop will link/copy files only, not directories, so your patch
should have no effect and is incorrect.

Either there's a bug in cp -p in msys, or the problem is elsewhere, and
I'd like to understand where, since I cannot guess with the info in the PR,
nor with my knowledge of the GNAT Makefiles.

Arno
Kai Tietz April 5, 2011, 9:29 a.m. UTC | #4
2011/4/5 Arnaud Charlet <charlet@adacore.com>:
>> Hmm, AFAICS is in Mafile.in the following line present:
>>
>> # Copy target independent sources
>>         $(foreach f,$(ADA_INCLUDE_SRCS) $(LIBGNAT_SRCS), \
>>           $(LN_S) $(fsrcpfx)ada/$(f) $(RTSDIR) ;) true
>>
>> which seems to me the cause for this patch.
>
> The above loop will link/copy files only, not directories, so your patch
> should have no effect and is incorrect.
>
> Either there's a bug in cp -p in msys, or the problem is elsewhere, and
> I'd like to understand where, since I cannot guess with the info in the PR,
> nor with my knowledge of the GNAT Makefiles.
>
> Arno
>

Well, there is a bug AFAICS. Issue is that 'ln -s file dir' fails, but
'ln -s file file1' works. See for this thread
http://lists.zerezo.com/mingw-users/msg03642.html, where this is
described. So it might be also a valid fix here to append to directory
the $f again.

Kai
Arnaud Charlet April 5, 2011, 9:32 a.m. UTC | #5
> Well, there is a bug AFAICS. Issue is that 'ln -s file dir' fails, but
> 'ln -s file file1' works. See for this thread
> http://lists.zerezo.com/mingw-users/msg03642.html, where this is
> described. So it might be also a valid fix here to append to directory
> the $f again.

OK, so it's indeed a bug in msys which should be fixed there IMO if it
does not support 'cp -p file dir'

Adding $f may cause command line limitations on some platforms, so I'd rather
avoid that.

Arno
Kai Tietz April 5, 2011, 9:45 a.m. UTC | #6
2011/4/5 Arnaud Charlet <charlet@adacore.com>:
>> Well, there is a bug AFAICS. Issue is that 'ln -s file dir' fails, but
>> 'ln -s file file1' works. See for this thread
>> http://lists.zerezo.com/mingw-users/msg03642.html, where this is
>> described. So it might be also a valid fix here to append to directory
>> the $f again.
>
> OK, so it's indeed a bug in msys which should be fixed there IMO if it
> does not support 'cp -p file dir'

I agree, and I read the threads about that there on mingw.org.  I
don't see a good chance that it get fixed soon there.  Nevertheless is
the msys-environment the only way to do a full bootstrap of native gcc
toolchain, so I would simply love to have this work-a-rounded it in
gcc.  But well, I won't die if it isn't. ;)

> Adding $f may cause command line limitations on some platforms, so I'd rather
> avoid that.
Yes, understood. But some lines down in Makefile we use LN_S with same
pathes, but with filenames on all two arguments.  So I think this fear
might be without reason here. (see section "Copy new target dependent
sources").

Regards,
Kai
Arnaud Charlet April 5, 2011, 9:58 a.m. UTC | #7
> I agree, and I read the threads about that there on mingw.org.  I
> don't see a good chance that it get fixed soon there.  Nevertheless is
> the msys-environment the only way to do a full bootstrap of native gcc
> toolchain, so I would simply love to have this work-a-rounded it in
> gcc.  But well, I won't die if it isn't. ;)

You can use other environments (e.g. cygwin or interix) to build native
gcc under Windows, with a bit of tweaking.

> Yes, understood. But some lines down in Makefile we use LN_S with same
> pathes, but with filenames on all two arguments.  So I think this fear
> might be without reason here. (see section "Copy new target dependent
> sources").

The section you are referring to concerns a different and much smaller set
of files, so will not be affected by command line limitations, so this is not
comparable.

Arno
Kai Tietz April 5, 2011, 10:13 a.m. UTC | #8
2011/4/5 Arnaud Charlet <charlet@adacore.com>:
>> I agree, and I read the threads about that there on mingw.org.  I
>> don't see a good chance that it get fixed soon there.  Nevertheless is
>> the msys-environment the only way to do a full bootstrap of native gcc
>> toolchain, so I would simply love to have this work-a-rounded it in
>> gcc.  But well, I won't die if it isn't. ;)
>
> You can use other environments (e.g. cygwin or interix) to build native
> gcc under Windows, with a bit of tweaking.

I know about that. And in fact I am use Wine for doing an native
compile. Nevertheless most users using msys for native windows.  Btw
that it would work on cygwin is more theory, as you need to replace
here system's make ... but well, I admit, if I tweak enough, its
possible. Interix is another nice approach, but for most people simply
unavailable due you need more then a windows-standard edition to use
it for free.

>> Yes, understood. But some lines down in Makefile we use LN_S with same
>> pathes, but with filenames on all two arguments.  So I think this fear
>> might be without reason here. (see section "Copy new target dependent
>> sources").
>
> The section you are referring to concerns a different and much smaller set
> of files, so will not be affected by command line limitations, so this is not
> comparable.

Sorry, here I am a bit curious. Maybe I am just unaware, but what have
the arguments of the LN_S call to do with the amount of entries in the
list, which are getting enumerated by foreach? The $f variable anyway
will contain just one filename, isn't it? Is such an foreach loop
unrolled before execution so that I have 'elements-in-foreach' *
'size-of-executed-command'?

Kai
Arnaud Charlet April 5, 2011, 10:19 a.m. UTC | #9
> I know about that. And in fact I am use Wine for doing an native
> compile. Nevertheless most users using msys for native windows.  Btw
> that it would work on cygwin is more theory,

It's not theory, it's what e.g. we do at AdaCore so it's very much
reality rather than theory.

> Sorry, here I am a bit curious. Maybe I am just unaware, but what have
> the arguments of the LN_S call to do with the amount of entries in the
> list, which are getting enumerated by foreach? The $f variable anyway
> will contain just one filename, isn't it? Is such an foreach loop
> unrolled before execution so that I have 'elements-in-foreach' *
> 'size-of-executed-command'?

Yes, GNU make 'foreach' will expand all the commands and concatenate them
into a single command line. In other words, foreach is simply a text
substition, unlike sh 'for' command.

Arno
Kai Tietz April 5, 2011, 10:22 a.m. UTC | #10
2011/4/5 Arnaud Charlet <charlet@adacore.com>:
>> I know about that. And in fact I am use Wine for doing an native
>> compile. Nevertheless most users using msys for native windows.  Btw
>> that it would work on cygwin is more theory,
>
> It's not theory, it's what e.g. we do at AdaCore so it's very much
> reality rather than theory.
Interesting

>> Sorry, here I am a bit curious. Maybe I am just unaware, but what have
>> the arguments of the LN_S call to do with the amount of entries in the
>> list, which are getting enumerated by foreach? The $f variable anyway
>> will contain just one filename, isn't it? Is such an foreach loop
>> unrolled before execution so that I have 'elements-in-foreach' *
>> 'size-of-executed-command'?
>
> Yes, GNU make 'foreach' will expand all the commands and concatenate them
> into a single command line. In other words, foreach is simply a text
> substition, unlike sh 'for' command.

Thanks for the explaining. I wasn't aware.

Kai
Charles Wilson April 5, 2011, 12:50 p.m. UTC | #11
On 4/5/2011 6:22 AM, Kai Tietz wrote:
> 2011/4/5 Arnaud Charlet <charlet@adacore.com>:
>>> I know about that. And in fact I am use Wine for doing an native
>>> compile. Nevertheless most users using msys for native windows.  Btw
>>> that it would work on cygwin is more theory,
>>
>> It's not theory, it's what e.g. we do at AdaCore so it's very much
>> reality rather than theory.
> Interesting

I'm one of the MSys "devs" (if you want to call the sporadic process of
updating MSys "development").  I'll take a look at implementing
	ln -s file dir
as synonymous with
	ln -s file dir/basename-of-file
in the next few days.

--
Chuck
Arnaud Charlet April 5, 2011, 1:21 p.m. UTC | #12
> I'm one of the MSys "devs" (if you want to call the sporadic process of
> updating MSys "development").  I'll take a look at implementing
> 	ln -s file dir
> as synonymous with
> 	ln -s file dir/basename-of-file
> in the next few days.

Thanks, although the case we're really interested in here is:

   cp -p file dir
as equivalent to
   cp -p file dir/basename-of-file

Arno
Charles Wilson April 5, 2011, 2:15 p.m. UTC | #13
On 4/5/2011 9:21 AM, Arnaud Charlet wrote:
>> I'm one of the MSys "devs" (if you want to call the sporadic process of
>> updating MSys "development").  I'll take a look at implementing
>> 	ln -s file dir
>> as synonymous with
>> 	ln -s file dir/basename-of-file
>> in the next few days.
> 
> Thanks, although the case we're really interested in here is:
> 
>    cp -p file dir
> as equivalent to
>    cp -p file dir/basename-of-file

Well, THAT already works on MSYS:

$ echo "test data" > foo
$ mkdir bar
$ cp -p foo bar
$ ls bar
foo

The problem with ln -s is this:

CYGWIN:

$ echo "test data" > foo
$ mkdir bar
$ ln -s foo bar
$ ls -l bar
total 1.0K
lrwxrwxrwx 1 owner group 3 Apr  5 09:57 foo -> foo

Note that this link, on cygwin, is broken anyway (and circular) but it
DOES succeed.  You get the same behavior on linux.

MSYS:
$ echo "test data" > foo
$ mkdir bar
$ ln -s foo bar
ln: creating symbolic link `bar/foo' to `foo': No such file or directory

This happens because MSYS's 'ln -s' (i.e. symlink(2)) can't resolve the
relative path "foo" from within the "bar" directory, so it can't figure
out how to 'fake' the symlink (MSYS always does fake symlinks, using
copy). Basically, this is a symptom of a larger issue: because MSYS
fakes symlinks using copy, there is no such thing as a "dangling
symlink" on MSYS -- and any attempt to create one will fail.

What I'm talking about is special casing this particular usage, so that
on MSYS:
$ ln -s file dir
acts like
$ cp -p file dir

Note that even on linux, if you wanted a non-dangling symlink, you'd
need to express the ln -s command as
$ ln -s ../file dir
because the path-to-target, if relative, needs to be relative from the
location of the symlink, not from the cwd.

So...is this still an issue with MSYS, or is it a bug in Ada's build
procedure that it deliberately tries to create a dangling symlink?

--
Chuck
Ralf Wildenhues April 5, 2011, 2:21 p.m. UTC | #14
* Charles Wilson wrote on Tue, Apr 05, 2011 at 04:15:02PM CEST:
> On 4/5/2011 9:21 AM, Arnaud Charlet wrote:
> >> I'm one of the MSys "devs" (if you want to call the sporadic process of
> >> updating MSys "development").  I'll take a look at implementing
> >> 	ln -s file dir
> >> as synonymous with
> >> 	ln -s file dir/basename-of-file
> >> in the next few days.

Please use LN_S *only* in the way that it is documented.  Let me quote 'info Autoconf --index LN_S':

 -- Macro: AC_PROG_LN_S
     If `ln -s' works on the current file system (the operating system
     and file system support symbolic links), set the output variable
     `LN_S' to `ln -s'; otherwise, if `ln' works, set `LN_S' to `ln',
     and otherwise set it to `cp -p'.

     If you make a link in a directory other than the current
     directory, its meaning depends on whether `ln' or `ln -s' is used.
     To safely create links using `$(LN_S)', either find out which form
     is used and adjust the arguments, or always invoke `ln' in the
     directory where the link is to be created.

     In other words, it does not work to do:
          $(LN_S) foo /x/bar

     Instead, do:

          (cd /x && $(LN_S) foo bar)

Thanks,
Ralf
Charles Wilson April 5, 2011, 3:58 p.m. UTC | #15
On 4/5/2011 10:21 AM, Ralf Wildenhues wrote:
> * Charles Wilson wrote on Tue, Apr 05, 2011 at 04:15:02PM CEST:
>> On 4/5/2011 9:21 AM, Arnaud Charlet wrote:
>>>> I'm one of the MSys "devs" (if you want to call the sporadic process of
>>>> updating MSys "development").  I'll take a look at implementing
>>>> 	ln -s file dir
>>>> as synonymous with
>>>> 	ln -s file dir/basename-of-file
>>>> in the next few days.
> 
> Please use LN_S *only* in the way that it is documented.  Let me quote 'info Autoconf --index LN_S':
> 
>  -- Macro: AC_PROG_LN_S
>      If `ln -s' works on the current file system (the operating system
>      and file system support symbolic links), set the output variable
>      `LN_S' to `ln -s'; otherwise, if `ln' works, set `LN_S' to `ln',
>      and otherwise set it to `cp -p'.
> 
>      If you make a link in a directory other than the current
>      directory, its meaning depends on whether `ln' or `ln -s' is used.
>      To safely create links using `$(LN_S)', either find out which form
>      is used and adjust the arguments, or always invoke `ln' in the
>      directory where the link is to be created.
> 
>      In other words, it does not work to do:
>           $(LN_S) foo /x/bar
> 
>      Instead, do:
> 
>           (cd /x && $(LN_S) foo bar)

OK, so you're saying "don't 'fix' MSys's ln -s behavior since doing so
would contravene normal expectations"

However, as Arno pointed out, right now for MSys LN_S is defined as "cp
-p" so it appears that "ln -s" behavior is a red herring.

This confuses me, because as I demonstrated earlier:

$ cp -p file dir

*works* on MSys.  So, I think we need more information from Kai about
WHAT exactly is failing here.  He claims that
	cp -p file dir
fails for him (and, wants to 'fix' it by adding -r, which implies that
some element of the foreach statement resolves to a *dir*, not a *file*
-- but Arno says that is not the case. /me = confused...)

What version of coreutils, and msys, are you using, Kai?  I tested with
msys-1.0.16 and coreutils-5.97-3.  Contact me offlist if you want help
running these details down.


As a side issue, it ALSO seems to me that Ada's Mafile.in is doing it
wrong, given Ralf's statements above:

	# Copy target independent sources
        $(foreach f,$(ADA_INCLUDE_SRCS) $(LIBGNAT_SRCS), \
          $(LN_S) $(fsrcpfx)ada/$(f) $(RTSDIR) ;) true

But as this isn't shell code (some sort of Ada buildfile? I'm not
familiar with building Ada), I'm not sure exactly how to "fix" it in the
event LN_S is ACTUALLY defined as "ln -s" or "ln" (which, recall, is NOT
the case on MSYS, which apparently uses cp -p).

--
Chuck
Arnaud Charlet April 5, 2011, 4:11 p.m. UTC | #16
> As a side issue, it ALSO seems to me that Ada's Mafile.in is doing it
> wrong, given Ralf's statements above:
> 
> 	# Copy target independent sources
>         $(foreach f,$(ADA_INCLUDE_SRCS) $(LIBGNAT_SRCS), \
>           $(LN_S) $(fsrcpfx)ada/$(f) $(RTSDIR) ;) true
> 
> But as this isn't shell code (some sort of Ada buildfile? I'm not
> familiar with building Ada),

This is standard GNU make code.

> I'm not sure exactly how to "fix" it in the
> event LN_S is ACTUALLY defined as "ln -s" or "ln" (which, recall, is NOT
> the case on MSYS, which apparently uses cp -p).

There is nothing broken here as far as I can tell, so nothing to "fix" here.

Arno
Charles Wilson April 5, 2011, 4:45 p.m. UTC | #17
On 4/5/2011 12:11 PM, Arnaud Charlet wrote:
>> As a side issue, it ALSO seems to me that Ada's Mafile.in is doing it
>> wrong, given Ralf's statements above:
>>
>> 	# Copy target independent sources
>>         $(foreach f,$(ADA_INCLUDE_SRCS) $(LIBGNAT_SRCS), \
>>           $(LN_S) $(fsrcpfx)ada/$(f) $(RTSDIR) ;) true
>>
>> But as this isn't shell code (some sort of Ada buildfile? I'm not
>> familiar with building Ada),
> 
> This is standard GNU make code.

Sorry, I always have to check the manual for the more unusual features
of make...like everything in Functions:: node.

>> I'm not sure exactly how to "fix" it in the
>> event LN_S is ACTUALLY defined as "ln -s" or "ln" (which, recall, is NOT
>> the case on MSYS, which apparently uses cp -p).
> 
> There is nothing broken here as far as I can tell, so nothing to "fix" here.

According to 'info Autoconf --index LN_S' as quoted by Ralf, it is not
*portable* to do
	$(LN_S) a_file a_dir
because it behaves differently depending on whether LN_S is "ln -s",
"ln" (or, as in this case, "cp -p"). This:
	$(LN_S) $(fsrcpfx)ada/$(f) $(RTSDIR)
fits that non-portable pattern -- assuming $(f) is always a file, and
$(RTSDIR) is actually a directory.  Ralf recommends that, for
portability, it should be changed to something like

	(cd $(RTSDIR) && $(LN_S) ??? $(basename $(f)) )

The only problem is how to express $(fsrcpfx)ada/$(f) as a relative path
from RTSDIR, or as an absolute path (maybe that's not a problem; I'm
unsure how fsrcpfx is defined).

--
Chuck
Arnaud Charlet April 5, 2011, 4:50 p.m. UTC | #18
> According to 'info Autoconf --index LN_S' as quoted by Ralf, it is not
> *portable* to do
> 	$(LN_S) a_file a_dir
> because it behaves differently depending on whether LN_S is "ln -s",
> "ln" (or, as in this case, "cp -p").

That is certainly true.

> This:
> 	$(LN_S) $(fsrcpfx)ada/$(f) $(RTSDIR)
> fits that non-portable pattern

That's wrong. The above is

$(LN_S) /full/path/to/a_file a_dir

which is quite different from

$(LN_S) a_file a_dir

and will work equally well with ln or ln -s or cp -p.

> Ralf recommends that, for
> portability, it should be changed to something like

And I recommend that we do nothing here because there's nothing broken.

Arno
Charles Wilson April 5, 2011, 5:01 p.m. UTC | #19
On 4/5/2011 12:50 PM, Arnaud Charlet wrote:
>> This:
>> 	$(LN_S) $(fsrcpfx)ada/$(f) $(RTSDIR)
>> fits that non-portable pattern
> 
> That's wrong. The above is
> 
> $(LN_S) /full/path/to/a_file a_dir
> 
> which is quite different from
> 
> $(LN_S) a_file a_dir
> 
> and will work equally well with ln or ln -s or cp -p.

A-HA! That's what I was missing; $a_file was an absolute path.
But...that works on MSYS too, with LN_S equal to all of those possibilities:

$ echo "test data" > /tmp/foo
$ ls -li /tmp/foo
3625195 -rw-r--r-- 1 owner group 10 Apr  5 12:53 /tmp/foo

$ mkdir bar
$ ln -s /tmp/foo bar
$ ls -li bar
total 1
2969862 -rw-r--r-- 1 owner group 10 Apr  5 12:53 foo

(Note that foo is NOT actually a symlink here, because of MSys's fake
behavior. It's a copy)

$ rm -rf bar
$ mkdir bar
$ ln /tmp/foo bar
$ ls -li bar
3625195 -rw-r--r-- 2 owner group 10 Apr  5 12:53 bar

(Note: in this case it is actually a hardlink -- and the link count has
increased. MSys supports hardlinks on NTFS file systems, with all the
usual caveats -- same device, etc)

$ rm -rf bar
$ mkdir bar
$ cp -p /tmp/foo bar
$ ls -li bar
total 1
1397010 -rw-r--r-- 1 owner group 10 Apr  5 12:53 foo


So, we really really need more info from Kai about WHAT exactly is
failing here.


>> Ralf recommends that, for
>> portability, it should be changed to something like
> 
> And I recommend that we do nothing here because there's nothing broken.

Ack.

--
Chuck
Russ Allbery April 6, 2011, 4:44 a.m. UTC | #20
Arnaud Charlet <charlet@adacore.com> writes:

> That's wrong. The above is

> $(LN_S) /full/path/to/a_file a_dir

> which is quite different from

> $(LN_S) a_file a_dir

> and will work equally well with ln or ln -s or cp -p.

This is not historically portable for ln -s.  Passing in a directory as
the second argument to ln and expecting that to be equivalent to ln -s
/path/to/file /path/to/directory/file (in other words, to use the basename
of the first argument) was originally behavior one could only rely on with
GNU utilities.  I remember modifying software to remove that assumption
when porting to various versions of UNIX.

Since then, the behavior you're relying on has been adopted by POSIX, and
I think all or nearly all of the UNIX vendors have implemented it in their
own versions of ln, so these days you may no longer care.  But there
definitely were UNIX systems where this didn't work and would result in an
error saying that a_dir already exists.
Arnaud Charlet April 6, 2011, 6:34 a.m. UTC | #21
> Since then, the behavior you're relying on has been adopted by POSIX, and
> I think all or nearly all of the UNIX vendors have implemented it in their
> own versions of ln, so these days you may no longer care.

To be more precise, we adopted this scheme at least 12 years ago on a wide
range of OSes and checked that this scheme did not cause any
portability issue on all the OSes where GNAT was ported. This hasn't
caused any problem on any OS where GNAT has been ported since then either.

Arno
Kai Tietz April 6, 2011, 6:42 a.m. UTC | #22
2011/4/6 Arnaud Charlet <charlet@adacore.com>:
>> Since then, the behavior you're relying on has been adopted by POSIX, and
>> I think all or nearly all of the UNIX vendors have implemented it in their
>> own versions of ln, so these days you may no longer care.
>
> To be more precise, we adopted this scheme at least 12 years ago on a wide
> range of OSes and checked that this scheme did not cause any
> portability issue on all the OSes where GNAT was ported. This hasn't
> caused any problem on any OS where GNAT has been ported since then either.
>
> Arno
>

Yes, I can't reproduce the issue described as #5 in bug-report.  So I
see here no real need to alter it for now. If there is a more detailed
description about the request of having for msys -pr as option, then
we can resurvive this issue. But for now I don't see here any need to
continue on this thread. Maybe Victor K. (the report of this issue)
can bring here more details.

Regards,
Kai
diff mbox

Patch

Index: Makefile.in
===================================================================
--- Makefile.in (revision 171925)
+++ Makefile.in (working copy)
@@ -1461,7 +1461,7 @@ 
 soext  = .exe
 hyphen = _
 LN = cp -p
-LN_S = cp -p
+LN_S = cp -pr

 .SUFFIXES: .sym