From 01ecb879a63941fbbe78c8f3d8683539d1f87d2e Mon Sep 17 00:00:00 2001 From: ailin-nemui Date: Wed, 27 May 2020 22:28:07 +0200 Subject: [PATCH] Add support for building in Termux-Android in meson - introduce cross perl - workaround for the android linker --- INSTALL | 32 +++++++-- configure.ac | 1 + docs/example-cross-android-aarch64.txt | 47 ++++++++++++ meson.build | 95 ++++++++++++++++++------- meson_options.txt | 1 + src/fe-common/core/fe-exec.c | 6 +- src/fe-fuzz/fe-common/core/theme-load.c | 4 +- src/perl/common/meson.build | 4 +- src/perl/irc/meson.build | 3 +- src/perl/meson.build | 14 ++-- src/perl/textui/meson.build | 3 +- src/perl/ui/meson.build | 3 +- 12 files changed, 167 insertions(+), 46 deletions(-) create mode 100644 docs/example-cross-android-aarch64.txt diff --git a/INSTALL b/INSTALL index 3476211f..712678e4 100644 --- a/INSTALL +++ b/INSTALL @@ -2,12 +2,12 @@ Irssi installation instructions ------------------------------- -To compile irssi you need: +To compile Irssi you need: - meson-0.49 build system with ninja-1.5 or greater - glib-2.28 or greater - openssl (for ssl support) -- perl-5.6 or greater (for perl support) +- perl-5.6 or greater (for Perl support) - terminfo or ncurses (for text frontend) For most people, this should work just fine: @@ -35,13 +35,13 @@ configure options --prefix - Specifies the path where irssi will be installed. - YES, you can install irssi WITHOUT ROOT permissions + Specifies the path where Irssi will be installed. + YES, you can install Irssi WITHOUT ROOT permissions by using --prefix=/home/dir -Dwith-proxy=yes / --with-proxy - Build the irssi proxy (see startup-HOWTO). + Build the Irssi proxy (see startup-HOWTO). -Dwith-perl=[yes|no] / --with-perl=[yes|no|module] @@ -70,9 +70,9 @@ configure options Build without text frontend If anything is in non-standard path, you can just give the paths in -CPPFLAGS and LIBS environment variable, eg.: +the -Dc_args and -Dc_link_args options variable, eg.: - CPPFLAGS=-I/opt/openssl/include LDFLAGS=-L/opt/openssl/lib ./configure + meson Build -Dc_args='-I/opt/openssl/include' -Dc_link_args='-L/opt/openssl/lib' @@ -112,6 +112,24 @@ perl static core fe System specific notes --------------------- + Android + +When cross compiling Irssi for Android, you can specify the path of +the cross-perl in the cross file. + +You may not have a cross-perl available. In that case, you will have +to manually supply the required Perl arguments in the cross file. See +the commented properties in the example cross file. + +An example cross file can be found in the docs folder. To use it, you +would call: + + meson Build --cross-file cross-android-aarch64.txt \ + --prefix /data/data/com.termux/files/usr \ + --libdir lib \ + -Dfhs-prefix=/data/data/com.termux/files/usr \ + + Cygwin Getting perl scripting to work needs a few things: diff --git a/configure.ac b/configure.ac index 9198fd67..14a79fb5 100644 --- a/configure.ac +++ b/configure.ac @@ -665,6 +665,7 @@ else want_gregex=no fi +AC_DEFINE([FHS_PREFIX], [""], [Alternate filesystem prefix for Termux]) AH_TEMPLATE(HAVE_GMODULE) AH_TEMPLATE(HAVE_SOCKS_H, [misc..]) AH_TEMPLATE(HAVE_STATIC_PERL) diff --git a/docs/example-cross-android-aarch64.txt b/docs/example-cross-android-aarch64.txt new file mode 100644 index 00000000..caae0383 --- /dev/null +++ b/docs/example-cross-android-aarch64.txt @@ -0,0 +1,47 @@ +[binaries] +ar = 'aarch64-linux-android-ar' +c = 'aarch64-linux-android-clang' +cpp = 'aarch64-linux-android-clang++' +ld = 'aarch64-linux-android-ld' +pkgconfig = '/home/builder/.termux-build/_cache/android-r20-api-24-v3/bin/aarch64-linux-android-pkg-config' +strip = 'aarch64-linux-android-strip' + +;; you have to substitute 5.30.2 with the Perl version, that can be +;; obtained by running ` miniperl -e 'print substr $^V, 1' ` + +perl = ['/home/builder/.termux-build/perl/src/miniperl', '-I/data/data/com.termux/files/usr/lib/perl5/5.30.2/aarch64-android', '-I/data/data/com.termux/files/usr/lib/perl5/5.30.2'] + +[properties] +needs_exe_wrapper = true +c_args = ['-fstack-protector-strong', '-Oz', '-I/data/data/com.termux/files/usr/include'] +cpp_args = ['-fstack-protector-strong', '-Oz', '-I/data/data/com.termux/files/usr/include'] +c_link_args = ['-L/data/data/com.termux/files/usr/lib', '-Wl,-rpath=/data/data/com.termux/files/usr/lib', '-Wl,--enable-new-dtags', '-Wl,--as-needed', '-Wl,-z,relro,-z,now', '-landroid-glob'] +cpp_link_args = ['-L/data/data/com.termux/files/usr/lib', '-Wl,-rpath=/data/data/com.termux/files/usr/lib', '-Wl,--enable-new-dtags', '-Wl,--as-needed', '-Wl,-z,relro,-z,now', '-landroid-glob'] + +;; if you do not have a cross-perl like miniperl available, you have +;; to specify the required options by uncommenting the following +;; properties + +;; you can get the proper values by running the commands on your +;; Android device: + +;; ` perl -V::version: ` +; perl_version = '5.30.2' +;; ` perl -MExtUtils::Embed -o ccopts ` +; perl_ccopts = ['-I/data/data/com.termux/files/usr/include', '-D_LARGEFILE_SOURCE', '-D_FILE_OFFSET_BITS=64', '-I/data/data/com.termux/files/usr/lib/perl5/5.30.2/aarch64-android/CORE'] +;; ` perl -MExtUtils::Embed -o ldopts ` +; perl_ldopts = ['-Wl,-E', '-I/data/data/com.termux/files/usr/include', '-L/data/data/com.termux/files/usr/lib/perl5/5.30.2/aarch64-android/CORE', '-lperl', '-lm', '-ldl'] +;; ` perl -V::archname: ` +; perl_archname = 'aarch64-android' +;; ` perl -V::installsitearch: ` +; perl_installsitearch = '/data/data/com.termux/files/usr/lib/perl5/site_perl/5.30.2/aarch64-android' +;; ` perl -V::installvendorarch: ` +; perl_installvendorarch = '' +;; ` perl -E 'say for @INC' ` +; perl_inc = ['/data/data/com.termux/files/usr/lib/perl5/site_perl/5.30.2/aarch64-android', '/data/data/com.termux/files/usr/lib/perl5/site_perl/5.30.2', '/data/data/com.termux/files/usr/lib/perl5/5.30.2/aarch64-android', '/data/data/com.termux/files/usr/lib/perl5/5.30.2'] + +[host_machine] +cpu_family = 'arm' +cpu = 'aarch64' +endian = 'little' +system = 'android' diff --git a/meson.build b/meson.build index cf982146..22ed9ec7 100644 --- a/meson.build +++ b/meson.build @@ -11,6 +11,12 @@ cc = meson.get_compiler('c') rootinc = include_directories('.') dep = [] textui_dep = [] +need_dl_cross_link = false +# The Android environment requires that all modules are linked to each other. +# See https://github.com/android/ndk/issues/201 +if host_machine.system() == 'android' + need_dl_cross_link = true +endif includedir = get_option('includedir') incdir = 'irssi' @@ -66,8 +72,13 @@ def_suppress_printf_fallback = '-D' + 'SUPPRESS_PRINTF_FALLBACK' # Help files # ############## -perl = find_program('perl') -run_command(perl, files('utils/syntax.pl')) +build_perl = find_program('perl', native : true) +if meson.is_cross_build() + cross_perl = find_program('perl') +else + cross_perl = build_perl +endif +run_command(build_perl, files('utils/syntax.pl')) ################### # irssi-version.h # @@ -313,34 +324,46 @@ if want_perl perl_rpath = '' #### ccopts #### - res = run_command(perl, '-MExtUtils::Embed', '-e', 'ccopts') - foreach fl : res.stdout().strip().split() - if fl.startswith('-D') or fl.startswith('-U') or fl.startswith('-I') or fl.startswith('-i') or fl.startswith('-f') or fl.startswith('-m') - perl_cflags += fl - endif + perl_ccopts = meson.get_cross_property('perl_ccopts', false) + if perl_ccopts == false + res = run_command(cross_perl, '-MExtUtils::Embed', '-e', 'ccopts') + perl_ccopts = res.stdout().strip().split() + endif + foreach fl : perl_ccopts + if fl.startswith('-D') or fl.startswith('-U') or fl.startswith('-I') or fl.startswith('-i') or fl.startswith('-f') or fl.startswith('-m') + perl_cflags += fl + endif endforeach perl_cflags += cc.get_supported_arguments('-fPIC') #### ldopts #### - res = run_command(perl, '-MExtUtils::Embed', '-e', 'ldopts') + perl_ldopts = meson.get_cross_property('perl_ldopts', false) + if perl_ldopts == false + res = run_command(cross_perl, '-MExtUtils::Embed', '-e', 'ldopts') + perl_ldopts = res.stdout().strip().split() + endif skip_libs = ['-ldb', '-ldbm', '-lndbm', '-lgdbm', '-lc', '-lposix', '-rdynamic'] - foreach fl : res.stdout().strip().split() - if not fl.startswith('-A') and not skip_libs.contains(fl) - if fl.startswith('-Wl,-rpath,') - perl_rpath = fl.split(',')[2] - perl_rpath_flags += fl - else - perl_ldflags += fl - endif - endif + foreach fl : perl_ldopts + if not fl.startswith('-A') and not skip_libs.contains(fl) + if fl.startswith('-Wl,-rpath,') + perl_rpath = fl.split(',')[2] + perl_rpath_flags += fl + else + perl_ldflags += fl + endif + endif endforeach + perl_version = meson.get_cross_property('perl_version', false) + if perl_version == false + perl_version = run_command(cross_perl, '-V::version:').stdout().split('\'')[1] + endif perl_dep = declare_dependency(compile_args : perl_cflags, link_args : perl_ldflags, - version : run_command(perl, '-V::version:').stdout().split('\'')[1]) + version : perl_version) #### - if not cc.run(''' + if not cc.compiles(''' #include #include int main() @@ -349,15 +372,18 @@ int main() return 0; } ''', args : perl_cflags + perl_ldflags + perl_rpath_flags, - name : 'working Perl support').compiled() + name : 'working Perl support') if require_perl error('error linking with perl libraries') else warning('error linking with perl libraries') endif else - xsubpp_file_c = run_command(perl, '-MExtUtils::ParseXS', '-Eprint $INC{"ExtUtils/ParseXS.pm"} =~ s{ParseXS\\.pm$}{xsubpp}r').stdout() - xsubpp = generator(perl, + xsubpp_file_c = meson.get_cross_property('perl_xsubpp', false) + if xsubpp_file_c == false + xsubpp_file_c = run_command(build_perl, '-MExtUtils::ParseXS', '-Eprint $INC{"ExtUtils/ParseXS.pm"} =~ s{ParseXS\\.pm$}{xsubpp}r').stdout() + endif + xsubpp = generator(build_perl, output : '@BASENAME@.c', capture : true, arguments : [ xsubpp_file_c, '@EXTRA_ARGS@', '@INPUT@' ], @@ -365,7 +391,7 @@ int main() xsubpp_file = files(xsubpp_file_c) if with_perl_lib == 'module' - perl_install_base = run_command(perl, '-MText::ParseWords=shellwords', '-e', 'grep { s/^INSTALL_BASE=// && print && exit } shellwords $ENV{PERL_MM_OPT}').stdout() + perl_install_base = run_command(build_perl, '-MText::ParseWords=shellwords', '-e', 'grep { s/^INSTALL_BASE=// && print && exit } shellwords $ENV{PERL_MM_OPT}').stdout() if perl_install_base == '' with_perl_lib = '' endif @@ -381,9 +407,16 @@ int main() set_perl_use_lib = false perl_library_dir = with_perl_lib + ' default' if with_perl_lib in ['site', 'vendor'] - perlmoddir = run_command(perl, '-V::install' + with_perl_lib + 'arch:').stdout().split('\'')[1] + perlmoddir = meson.get_cross_property('perl_install' + with_perl_lib + 'arch', false) + if perlmoddir == false + perlmoddir = run_command(cross_perl, '-V::install' + with_perl_lib + 'arch:').stdout().split('\'')[1] + endif elif with_perl_lib == 'module' - perlmoddir = perl_install_base / 'lib' / 'perl5' / run_command(perl, '-V::archname:').stdout().split('\'')[1] + perl_archname = meson.get_cross_property('perl_archname', false) + if perl_archname == false + perl_archname = run_command(cross_perl, '-V::archname:').stdout().split('\'')[1] + endif + perlmoddir = perl_install_base / 'lib' / 'perl5' / perl_archname endif elif with_perl_lib == '' set_perl_use_lib = true @@ -399,7 +432,12 @@ int main() perl_use_lib = get_option('prefix') / perlmoddir if set_perl_use_lib - set_perl_use_lib = run_command(perl, '-e', 'exit ! grep $_ eq $ARGV[0], grep /^\\//, @INC', perl_use_lib).returncode() != 0 + perl_inc = meson.get_cross_property('perl_inc', false) + if perl_inc == false + set_perl_use_lib = run_command(cross_perl, '-e', 'exit ! grep $_ eq $ARGV[0], grep /^\\//, @INC', perl_use_lib).returncode() != 0 + else + set_perl_use_lib = not perl_inc.contains(perl_use_lib) + endif if not set_perl_use_lib perl_library_dir += ' - other path in @INC' else @@ -460,6 +498,10 @@ dep_cflagsonly = [] foreach d : dep dep_cflagsonly += d.partial_dependency(includes : true, compile_args : true) endforeach +dl_cross_dep = [] +if need_dl_cross_link + dl_cross_dep = dep +endif ################## # irssi-config.h # @@ -473,6 +515,7 @@ conf.set('HAVE_SOCKS', false, description : 'Build with socks support') conf.set('TERM_TRUECOLOR', want_truecolor, description : 'true color support in terminal') conf.set('USE_GREGEX', want_gregex, description : 'use GRegex for regular expressions') conf.set10('_DARWIN_USE_64_BIT_INODE', true, description : 'Enable large inode numbers on Mac OS X 10.5.') +conf.set_quoted('FHS_PREFIX', get_option('fhs-prefix')) headers = [ 'sys/ioctl.h', diff --git a/meson_options.txt b/meson_options.txt index c975db3a..5dc9c514 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -14,3 +14,4 @@ option('with-capsicum', type : 'combo', description : 'Build with Capsicum option('static-dependency', type : 'combo', description : 'Request static dependencies', choices : ['no', 'yes']) option('install-glib', type : 'combo', description : 'Download and install GLib for you', choices : ['no', 'yes', 'force']) option('docdir', type : 'string', description : 'Documentation directory') +option('fhs-prefix', type : 'string', description : 'System prefix for Termux') diff --git a/src/fe-common/core/fe-exec.c b/src/fe-common/core/fe-exec.c index 58471345..dcd4ecb5 100644 --- a/src/fe-common/core/fe-exec.c +++ b/src/fe-common/core/fe-exec.c @@ -281,8 +281,8 @@ static void exec_show_list(void) static void process_exec(PROCESS_REC *rec, const char *cmd) { - const char *shell_args[4] = { "/bin/sh", "-c", NULL, NULL }; - char **args; + const char *shell_args[4] = { FHS_PREFIX "/bin/sh", "-c", NULL, NULL }; + char **args; int in[2], out[2]; int n; @@ -341,7 +341,7 @@ static void process_exec(PROCESS_REC *rec, const char *cmd) if (rec->shell) { execvp(shell_args[0], (char **) shell_args); - fprintf(stderr, "Exec: /bin/sh: %s\n", g_strerror(errno)); + fprintf(stderr, "Exec: " FHS_PREFIX "/bin/sh: %s\n", g_strerror(errno)); } else { args = g_strsplit(cmd, " ", -1); execvp(args[0], args); diff --git a/src/fe-fuzz/fe-common/core/theme-load.c b/src/fe-fuzz/fe-common/core/theme-load.c index faa063bb..f6db8f5f 100644 --- a/src/fe-fuzz/fe-common/core/theme-load.c +++ b/src/fe-fuzz/fe-common/core/theme-load.c @@ -37,7 +37,7 @@ #include int LLVMFuzzerInitialize(int *argc, char ***argv) { - char *irssi_argv[] = {*argv[0], "--home", "/tmp/irssi", NULL}; + char *irssi_argv[] = { *argv[0], "--home", FHS_PREFIX "/tmp/irssi", NULL }; int irssi_argc = sizeof(irssi_argv) / sizeof(char *) - 1; #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION g_log_set_null_logger(); @@ -57,7 +57,7 @@ int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { THEME_REC *theme; gchar *copy = g_strndup((const gchar *)data, size); - FILE *fp = fopen("/tmp/irssi/fuzz.theme", "wb"); + FILE *fp = fopen(FHS_PREFIX "/tmp/irssi/fuzz.theme", "wb"); if (fp) { fwrite(copy, strlen(copy), 1, fp); fclose(fp); diff --git a/src/perl/common/meson.build b/src/perl/common/meson.build index 2cbf7f4c..f2a69bc9 100644 --- a/src/perl/common/meson.build +++ b/src/perl/common/meson.build @@ -1,4 +1,5 @@ -libperl_common_a = shared_module('Irssi', + +libperl_Irssi_a = shared_module('Irssi', [ xsubpp.process( files( 'Channel.xs', @@ -24,6 +25,7 @@ libperl_common_a = shared_module('Irssi', include_directories : rootinc, implicit_include_directories : true, dependencies : dep + [ perl_dep ], + link_with : dl_cross_perl_core, ) install_headers( diff --git a/src/perl/irc/meson.build b/src/perl/irc/meson.build index 7d77e0c1..0a8fd9f9 100644 --- a/src/perl/irc/meson.build +++ b/src/perl/irc/meson.build @@ -1,4 +1,4 @@ -libperl_irc_a = shared_module('Irc', +libperl_Irssi_Irc_a = shared_module('Irc', [ xsubpp.process( files( 'Channel.xs', @@ -26,6 +26,7 @@ libperl_irc_a = shared_module('Irc', include_directories : rootinc, implicit_include_directories : true, dependencies : dep + [ perl_dep ], + link_with : dl_cross_perl_core, ) install_headers( diff --git a/src/perl/meson.build b/src/perl/meson.build index a9f1296a..6a2aaa85 100644 --- a/src/perl/meson.build +++ b/src/perl/meson.build @@ -4,7 +4,7 @@ perl_signals_list_h = custom_target('perl-signals-list.h', output : 'perl-signals-list.h', capture : true, depend_files : files('get-signals.pl'), - command : [perl, files('get-signals.pl'), '@INPUT@'], + command : [build_perl, files('get-signals.pl'), '@INPUT@'], ) irssi_core_pl_h = custom_target('irssi-core.pl.h', @@ -14,7 +14,7 @@ irssi_core_pl_h = custom_target('irssi-core.pl.h', command : [file2header, '@INPUT@', 'irssi_core_code'], ) -shared_module('perl_core', +libperl_core_a = shared_module('perl_core', files( 'perl-common.c', 'perl-core.c', @@ -35,11 +35,16 @@ shared_module('perl_core', install_dir : moduledir, install_rpath : perl_rpath, build_rpath : perl_rpath, - dependencies : dep_cflagsonly + [ perl_dep ], + dependencies : dep_cflagsonly + [ perl_dep ] + dl_cross_dep, override_options : ['b_asneeded=false'], ) -shared_module('fe_perl', +dl_cross_perl_core = [] +if need_dl_cross_link + dl_cross_perl_core += libperl_core_a +endif + +libfe_perl_a = shared_module('fe_perl', files( 'module-formats.c', 'perl-fe.c', @@ -52,6 +57,7 @@ shared_module('fe_perl', install : true, install_dir : moduledir, dependencies : dep, + link_with : dl_cross_perl_core, ) subdir('common') diff --git a/src/perl/textui/meson.build b/src/perl/textui/meson.build index 61362d52..1705fa36 100644 --- a/src/perl/textui/meson.build +++ b/src/perl/textui/meson.build @@ -1,4 +1,4 @@ -libperl_textui_a = shared_module('TextUI', +libperl_Irssi_TextUI_a = shared_module('TextUI', [ xsubpp.process( files( 'Statusbar.xs', @@ -22,6 +22,7 @@ libperl_textui_a = shared_module('TextUI', include_directories : rootinc, implicit_include_directories : true, dependencies : dep + [ perl_dep ], + link_with : dl_cross_perl_core, ) install_headers( diff --git a/src/perl/ui/meson.build b/src/perl/ui/meson.build index eca864dd..14bc7699 100644 --- a/src/perl/ui/meson.build +++ b/src/perl/ui/meson.build @@ -1,4 +1,4 @@ -libperl_ui_a = shared_module('UI', +libperl_Irssi_UI_a = shared_module('UI', [ xsubpp.process( files( 'Formats.xs', @@ -20,6 +20,7 @@ libperl_ui_a = shared_module('UI', include_directories : rootinc, implicit_include_directories : true, dependencies : dep + [ perl_dep ], + link_with : dl_cross_perl_core, ) install_headers(