Opened 12 months ago

Closed 10 months ago

Last modified 10 months ago

#61784 closed defect (fixed)

pv is broken in Apple Silicon

Reported by: hpux735 (William Dillon) Owned by: eborisch (Eric A. Borisch)
Priority: Normal Milestone:
Component: ports Version: 2.6.4
Keywords: bigsur, arm64, upstream Cc:
Port: pv

Description

There is a build failure in CI (and my local machine) for pv related to stat64's deprecation. I was able to fix it locally, and it's fairly straight-forward, though it's hackish. The root of the problem is that autoconf is able to determine that the stat64 function exists, and therefore thinks that the structure exists, and doesn't include a set of defines that make it OK. I was able to edit config.h to clear the HAVE_STAT64 flag and the program compiled. I have a message out to the pv author. I'm not quite competent in autotools, and I'm not sure what the right way to fix it is, but it appears that the Portfile already has a patch to deal with stat64, so maybe that could be extended without changing upstream?

% diff fixed/config.h broken/config.h
21a22
> #define HAVE_STAT64 1

Change History (6)

comment:1 Changed 12 months ago by jmroot (Joshua Root)

Owner: set to eborisch
Status: newassigned

comment:2 Changed 11 months ago by mhberger

Hi, I have had a go at a fix and have created a pull request

https://github.com/macports/macports-ports/pull/9800

comment:3 Changed 11 months ago by kencu (Ken)

there's no log or config.log here, so we can't really say what might be going on.

It looks like your PR just removes the flag; although that might well work on one system to fix a build, it doesn't sound like the proper fix, and seems likely to break builds elsewhere...

comment:4 Changed 10 months ago by mhberger

I have done a bit of digging and have come up with something, but not necessarily the ideal soluton.

Basically autoconf takes autoconf/configure.in and creates configure, which then tests for availability of certain functions and then creates #defines indicating availability of certain functions.

e.g. the autoconf function AC_CHECK_FUNCS(stat64) generates bash code in configure which tests for availability of stat64 and if function is available writes #define HAVE_STAT64 1.

This code does this by creating a C program conftest.c and then compiles, links and runs it.

This C program does not pick up the absence of the symbol at compile time, but only at link time. i.e. by defining a char stat64 ();, a compile only will not fail with an unknown symbol.

See the code example 1 below and try the following on either a Silicon or Intel Mac.

Test 1 – using Joe symbol

Change all occurrences of stat64 to Joe and compile without linking by using gcc -S sample.c. This will report no errors. This is because we have char Joe ();.

However if we compile and link gcc sample.c -o sample, it fails with a linking error because it cannot find symbol Joe at link time.

Test 2 – using stat64 symbol

Try the same two tests using stat64 rather than Joe.

Both the compile only and compile/link will work on both Silicon and Intel.

The compile works because we have a char stat64 ();.

On the both systems tested, the link works because stat64 is defined as a symbol in /usr/lib/dyld which can be seen using

xxd /usr/lib/dyld | grep stat64

In other words, the gcc conftest.c test will always return true if the symbol it is testing for can be resolved at link time.

How does this affect the pv port?

The pv port uses and needs stat64.

The code in the pv include ifndef HAVE_STAT64 does not actually evaluate to true, so the redefinition of stat64 to stat does not happen here.

On Intel Macs, the stat64 is not redefined to stat by standard Apple includes, but compiles with deprecation warnings, and still links and runs.

On the Silicon Mac, the stat64 is not redefined to stat by standard Apple includes, so compiling pv code generates a compile warning.

This is demonstrated by compiling, linking and running code example 2.

So to get pv to build for Silicon, we have to explicitly add a set of defines for this that will run on Silicon and not on Intel i.e. check for __arm64__.

# if __arm64__
#  define stat64 stat
#  define fstat64 fstat
#  define lstat64 lstat
# endif

Example 1 – Test code generated by configure

/* confdefs.h */
#define PACKAGE_NAME ""
#define PACKAGE_TARNAME ""
#define PACKAGE_VERSION ""
#define PACKAGE_STRING ""
#define PACKAGE_BUGREPORT ""
#define PACKAGE_URL ""
/* end confdefs.h.  */
/* Define stat64 to an innocuous variant, in case <limits.h> declares stat64.
   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
#define stat64 innocuous_stat64

/* System header to define __stub macros and hopefully few prototypes,
    which can conflict with char stat64 (); below.
    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
    <limits.h> exists even on freestanding compilers.  */

#ifdef __STDC__
# include <limits.h>
#else
# include <assert.h>
#endif

#undef stat64

/* Override any GCC internal prototype to avoid an error.
   Use char because int might match the return type of a GCC
   builtin and then its argument prototype would still apply.  */
#ifdef __cplusplus
extern "C"
#endif
char stat64 ();
/* The GNU C library defines this for functions which it implements
    to always fail with ENOSYS.  Some functions are actually named
    something starting with __ and the normal name is an alias.  */
#if defined __stub_stat64 || defined __stub___stat64
choke me
#endif

int
main ()
{
return stat64 ();
  ;
  return 0;
}

Example 2 – Simple program showing use of stat64

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>

// If following block is uncommented, program compiles, links and runs on Intel
//   (with deprecation warnings) and Silicon.
//   On Intel examining the built file `otool -LIV` shows `stat64` being used.
//   On Silicon examining the built file `otool -LIV` shows `stat` being used.
// If following block is commented out (add leading //), then it compiles, links
//   and runs on Intel (with deprecation warnings) but fails to compile on Silicon
//   On Intel examining the built file `otool -LIV` shows `stat64` being used.
#if __arm64__
#define stat64 stat
#endif

int main() {
  struct stat64 info;

  if (stat64("/", &info) != 0)
    perror("stat() error");
  else {
    puts("stat() returned the following information about root f/s:");
    printf("  inode:   %d\n",   (int) info.st_ino);
    printf(" dev id:   %d\n",   (int) info.st_dev);
    printf("   mode:   %08x\n",       info.st_mode);
    printf("  links:   %d\n",         info.st_nlink);
    printf("    uid:   %d\n",   (int) info.st_uid);
    printf("    gid:   %d\n",   (int) info.st_gid);
  }
}

Last edited 10 months ago by mhberger (previous) (diff)

comment:5 Changed 10 months ago by mhberger <21727+mhberger@…>

Resolution: fixed
Status: assignedclosed

In 3a5dc026ec2e59849cc45a4e21d5978b64a989a0/macports-ports (master):

pv: Fix detection of stat64 in Apple Silicon. (https://github.com/macports/macports-ports/pull/9800)

Fixes: #61784

Take 7. Tidy up logic when configuring cppflags. Thanks @eborisch.

Co-authored-by: Mark Berger <mark.berger@…>

comment:6 Changed 10 months ago by ryandesign (Ryan Schmidt)

This change is not correct for the universal variant. The port already uses the muniversal portgroup, and the change should be redesigned with that in mind.

Note: See TracTickets for help on using tickets.