Perl-Toolchain-Gang / ExtUtils-MakeMaker

Perl module to make Makefiles and build modules (what backs Makefile.PL)
https://metacpan.org/release/ExtUtils-MakeMaker
64 stars 76 forks source link

How to link with a framework on macOS ? #393

Open hakonhagland opened 3 years ago

hakonhagland commented 3 years ago

See this question on stackoverflow. In order to compile the following C program on macOS :

#include <ApplicationServices/ApplicationServices.h>
#include <unistd.h>

void mmove(int x, int y);

int main() {
    mmove(100,100);
}

void mmove(int x, int y) {
    CGEventRef move = CGEventCreateMouseEvent( NULL, kCGEventMouseMoved, CGPointMake(x, y), kCGMouseButtonLeft );
    CGEventPost(kCGHIDEventTap, move);
    CFRelease(move);
}

the following command line can be used:

cc -o foo foo.c -framework ApplicationServices

But passing LIBS => " -framework ApplicationServices" to WriteMakefile() does not work. For example:

$ perl -MData::Dumper -MExtUtils::Liblist -E ' print Dumper(ExtUtils::Liblist->ext("-framework ApplicationServices"))'
$VAR1 = '';
$VAR2 = '';
$VAR3 = '';
$VAR4 = '';

However, passing LDDLFLAGS => "$Config{lddlflags} -framework ApplicationServices" does work, but shouldn't it be possible to use LIBS here ?

mohawk2 commented 3 years ago

It sounds like Liblist would need to gain knowledge about -framework. To do so would be platform-specific, which could either be crowbarred in as-is, or be done after a somewhat-needed restructuring of Liblist to fit with (and probably be incorporated into) the MM_* modules.

Leont commented 3 years ago

It sounds like Liblist would need to gain knowledge about -framework.

Yeah. Liblist keeps being a PITA.

kiwiroy commented 3 years ago

Workaround:

Add a library (e.g. -lm) that can be found and increment $found so @extralibs are returned.

LIBS => "-lm -framework ApplicationServices"

https://github.com/Perl-Toolchain-Gang/ExtUtils-MakeMaker/blob/ff859c3d4e0dc725a1a216f8c8a4d2704f255148/lib/ExtUtils/Liblist/Kid.pm#L274-L279

Gaining knowledge:

It might be that the standard paths get searched - from Including Frameworks

/System/Library/Frameworks directory and the /Library/Frameworks directory

and possibly $DYLD_FRAMEWORK_PATH.

diff --git a/lib/ExtUtils/Liblist/Kid.pm b/lib/ExtUtils/Liblist/Kid.pm
index 5eb8a8a0..3fd56e4b 100644
--- a/lib/ExtUtils/Liblist/Kid.pm
+++ b/lib/ExtUtils/Liblist/Kid.pm
@@ -97,6 +97,12 @@ sub _unix_os2_ext {
         }

         if ( $thislib =~ m!^-Wl,! ) {
+            if (@extralibs && $extralibs[$#extralibs] eq '-Wl,-framework') {
+              (my $framework = $thislib) =~ s/^-Wl,//;
+              for (qw(/System/Library/Frameworks /Library/Frameworks), split(/:/, $ENV{DYLD_FRAMEWORK_PATH})) {
+                $found++ if (-d File::Spec->catdir($_, "$framework.framework"));
+              }
+            }
             push( @extralibs,  $thislib );
             push( @ldloadlibs, $thislib );
             next;