timbunce / devel-nytprof

Devel::NYTProf is a powerful feature-rich source code profiler for Perl. (Mostly in maintenance mode, so PRs are much more likely to be acted upon than Issues.)
http://blog.timbunce.org/tag/nytprof/
67 stars 50 forks source link

Using a custom include and libs path for zlib #218

Open vrkosk opened 2 months ago

vrkosk commented 2 months ago

I'm using a bare bones sysroot (same as in issue #217 in fact) that doesn't have zlib installed. I have compiled and installed zlib in a different path, say $XYZZY, so I'd like to set a custom include path $XYZZY/include and custom linker flag -L$XYZZY/lib.

Makefile.PL has my $INCLUDE; variable, which is passed to WriteMakeFile(), but the variable is always undef. Solution is:

 push @h_dirs, qw(/include /usr/include /usr/local/include /usr/include/mach);
 @h_dirs = grep { -d $_ } @h_dirs;

+$INCLUDE = join(' ', map { sprintf('-I%s', $_) } split /:/, $ENV{INCLUDE}) if $ENV{INCLUDE};

Then configure as:

INCLUDE=$XYZZY/include perl Makefile.PL

However, there's no mechanism to set a custom library path. Essentially, I want to push something to @libs before it's passed to WriteMakeFile().

jkeenan commented 2 months ago

I've been investigating your arguments in several branches in my git fork of the devel-nytprof repository. Here are my findings.

First, I can confirm that the statement my $INCLUDE; in Makefile.PL is currently extraneous because $INCLUDE is never assigned to; consequently, the value assigned to the INC element in the arguments passed to WriteMakefile() is always undefined. See:

branch: https://github.com/jkeenan/devel-nytprof/tree/gh-218-INC-20240503 commit: https://github.com/jkeenan/devel-nytprof/commit/429832555e7b3bb7c2a38a8567bbdaba4566aad2

Second, notwithstanding the above, I believe you can currently pass custom header files to WriteMakefile(). I demonstrate this in the following:

branch: https://github.com/jkeenan/devel-nytprof/tree/debug-makefilepl-20240504 https://github.com/jkeenan/devel-nytprof/commit/a399e8e8e1566dcfdd67566b4bcda736d995cba1

In that branch I insert some print statements for debugging into Makefile.PL to display the contents of its lexical variables, then I merge in the first branch. Now if in my local checkout of the second branch I say:

$ export INCLUDE=/tmp/include
$ mkdir -p $INCLUDE
$ touch $INCLUDE/custom-headers.h
$ perl Makefile.PL

... I now observe:

$ perl Makefile.PL 2>&1 | grep -C2 custom
  cursesw.h               /usr/include
  cursslk.h               /usr/include
  custom-headers.h        /tmp/include
  dirent.h                /usr/include
  dlfcn.h                 /usr/include

Wouldn't that satisfy your needs?

vrkosk commented 2 months ago

Yes, that solves it for the header file path. (I can't see how changing INC => $INCLUDE to INC => undef has fixed it, though! In both cases INC is undef, so I must be missing something.)

There is the remaining issue with setting the library path or passing the linker flag -L/some/path. If it can be done with an environment variable, that would be easiest.

jkeenan commented 2 months ago

I am extremely reluctant to modify Devel-NYTProf to further accommodate your concerns. However, the following documentation excerpts may suggest a path forward for you.

From Devel-NYTProf's Makefile.PL:

 79 # See lib/ExtUtils/MakeMaker.pm for details of how to influence
 80 # the contents of the Makefile that is written.
 81 my %mm_opts;
 82 my @libs = ();
 83 
...
 92 foreach (@hdr_match_lib) {
 93     my ($header, $regexp, $define, $libs) = @$_;
 94     if (my $result = search_h_file($header, $regexp)) {
 95         print "Found $result in $header\n";
 96         push @libs, $libs if $libs;
 97         $mm_opts{DEFINE} .= " $define" if $define;
 98     }
 99 }
100 
...
176 WriteMakefile(
...
182     LIBS      => [join ' ', @libs],

Now we call perldoc ExtUtil::MakeMaker to see how it uses LIBS:

LIBS
  An anonymous array of alternative library specifications to be
  searched for (in order) until at least one library is found. E.g.

    'LIBS' => ["-lgdbm", "-ldbm -lfoo", "-L/path -ldbm.nfs"]

Now we call man gcc :

   -llibrary
   -l library
       Search the library named library when linking.  (The second alternative with the
       library as a separate argument is only for POSIX compliance and is not recommended.)

       The -l option is passed directly to the linker by GCC.  Refer to your linker
       documentation for exact details.  The general description below applies to the GNU
       linker.

       The linker searches a standard list of directories for the library.  The directories
       searched include several standard system directories plus any that you specify with
       -L.
...
   -Ldir
       Add directory dir to the list of directories to be searched for -l.

I doubt the following patch will completely work, but it may provide a starting point for your further explorations.

$ cat gh-218-altlink.diff 
diff --git a/Makefile.PL b/Makefile.PL
index 6ace18b..11f46f1 100644
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -44,6 +44,7 @@ GetOptions(
     'zlib!'     => \(my $opt_zlib=1),       # --nozlib to disallow use of zlib
     'gettime!'  => \(my $opt_gettime=1),    # --nogettime to disallow use of POSIX clock_gettime
     'machtime!' => \(my $opt_machtime=1),   # --nomachtime to disallow use of mac osx clock
+    'altlink=s'   => \(my $opt_altlink),    # additional linker arguments
 ) or exit 1;

 if (not defined $opt_assert) {
@@ -98,6 +99,10 @@ foreach (@hdr_match_lib) {
     }
 }

+if ($opt_altlink) {
+    push @libs, $opt_altlink;
+}
+
 if ($opt_assert or (not defined $opt_assert and $is_developer)) {
     warn "Assertion testing enabled\n";
     $mm_opts{DEFINE} .= " -DUSE_HARD_ASSERT";
vrkosk commented 2 months ago

I agree it's a niche use case. Before submitting this bug report, I edited Makefile.PL locally and did almost exactly what you describe: push the additional linker argument to @libs. You can override the LIBS environment variable like:

LIBS= perl Makefile.PL

But this removes the default flags like -lrt. A brittle workaround is to run perl Makefile.PL then make, and look at the arguments passed to ld. Then, define LIBS with those arguments plus the custom path -L/some/path. That's why I was looking for something more robust!

jkeenan commented 2 months ago

I agree it's a niche use case. Before submitting this bug report, I edited Makefile.PL locally and did almost exactly what you describe: push the additional linker argument to @libs. You can override the LIBS environment variable like:

LIBS= perl Makefile.PL

But this removes the default flags like -lrt. A brittle workaround is to run perl Makefile.PL then make, and look at the arguments passed to ld. Then, define LIBS with those arguments plus the custom path -L/some/path. That's why I was looking for something more robust!

Well, I will not be the person to provide that something more robust. ;-) I assumed (partial) maintenance responsibilities for Devel-NYTProf only because changes in Perl 5 several years ago were causing test failures. I have no expertise in many areas of the library (C, XS, Javascript) and so I only handle changes that are within my scope (Perl) and that I can be absolutely certain will do no harm. Consequently, I can't consider a request for a new feature unless there is wide demand for it.

So if you have something that you have a workaround that works for you, please use it!