Introduce an Android window system port for GNU Emacs
* src/xterm.h: New fields `quit_keysym' and `quit_keysym_time'. * src/xterm.c (handle_one_xevent): Check for the quit keysym, and set Vquit_flag upon witnessing two clicks in rapid succession. (x_term_init): Set `quit_keysym'. (init_xterm): Fix typo in name of `register_textconv_interface'. (syms_of_xterm) <Vx_toolkit_scroll_bars>: Describe its default value on android. * src/xfns.c (xic_string_conversion_callback): Pass `0' as the last argument to textconv_query. (Fx_server_vendor, Fx_server_version): Document return values on Android. * src/xfaces.c (Fx_family_fonts, set_lface_from_font): Use FRAME_RES instead of FRAME_RES_Y, respecting user preferences on window systems that have distinct display and font scaling factors. (Fx_load_color_file): Call `emacs_fclose', not fclose. * src/xdisp.c (tab_bar_item_info): Allow `close_p' to be NULL. (get_tab_bar_item): Update commentary to reflect that change. (get_tab_bar_item_kbd): New function, resembling get_tab_bar_item. (build_desired_tool_bar_string): Clear `f->tool_bar_wraps_p'; insert new line characters if a QCwrap item is encountered, and set f->tool_bar_wrap_p. Replace characters beyond the end of the tool bar with spaces. (display_tool_bar_line): Move iterator to the next line if in contact with an explicit line-wrap item. (redisplay_internal): If there are newline characters in the tool bar, refrain from coercing each row into being identically tall. Don't call `set_tty_color_mode' on Android. (mark_window_display_accurate_1): Report changes to the point and mark to input methods. (display_menu_bar): Adjust ifdefs to allow non-X window systems to use the built-in menu bar. (draw_row_with_mouse_face): Don't call TTY functions on Android. (note_mouse_highlight): Call `popup_activated' on Android. (expose_frame): Correctly work on the menu bar window. (gui_union_rectangles): New function. * src/window.h (struct window): New fields for recording the last window and point positions, along with an ephemeral position used during IM text conversion. (WINDOW_MENU_BAR_P): Correct definition for non-X window systems without external menu bars. * src/window.c (replace_buffer_in_windows): Call Qreplace_buffer_in_windows only when bound. * src/w32proc.c (sys_spawnve): Pass extra argument to openp. * src/w32font.c (fill_in_logfont): Use font scaling factor, not the display scaling factor. * src/w32.c (check_windows_init_file): Pass extra argument to openp. * src/verbose.mk.in (AM_V_JAVAC, AM_V_DX, AM_V_AAPT) (AM_V_ZIPALIGN, AM_V_SILENT): New variables. * src/textconv.h (struct textconv_interface): New `point_changed', `compose_region_changed' and `notify_conversion'. Add declarations for new functions. * src/textconv.c (TEXTCONV_DEBUG): New macro. (suppress_conversion_count): New variable. (enum textconv_batch_edit_flags): New flag. (copy_buffer): Don't overwrite text before the gap with the text after. (get_mark, select_window): New functions. (textconv_query): New argument FLAGS. Contingent upon its value, use the previous point or mark or skip the conversion region. (sync_overlay, record_buffer_change, reset_frame_state) (detect_conversion_events, restore_selected_window) (really_commit_text, really_finish_composing_text) (really_set_composing_region, really_delete_composing_text) (really_request_point_update, really_set_point_and_mark) (complete_edit): New functions. (struct complete_edit_check_context): New structure; store in it the result of editing operations. (complete_edit_check, handle_pending_conversion_events_1) (decrement_inside, handle_pending_conversion_events) (start_batch_edit, end_batch_edit, commit_text) (set_composing_text, textconv_set_point_and_mark) (request_point_update, textconv_barrier, get_extracted_text) (get_surrounding_text, conversion_disabled_p) (report_selected_window_change, report_point_change) (disable_text_conversion, resume_text_conversion) (register_textconv_interface, check_postponed_buffers) (postponed_buffers, Fset_text_conversion_style) (syms_of_textconv) <Qaction, Qtext_conversion, Qpush_mark, Qunderline, Qoverriding_text_conversion_style, Vtext_conversion_edits, Voverriding_text_conversion_style, Vtext_conversion_face>: New functions, symbols and variables. * src/terminal.c (Fterminal_live_p): Return Qandroid if type is output_android. * src/termhooks.h (enum output_method): Add `output_android'. (struct terminal) <display_info>: Add union constituent field for `android'. <query_colors>: Define on Android as well. (TERMINAL_FONT_CACHE) [HAVE_ANDROID]: Return the inappropriately named font cache field on Android. * src/term.c (string_cost, string_cost_one_line, per_line_cost) (calculate_costs, produce_glyphs, produce_glyphs, tty_capable_p) (tty_capable_p, device, init_tty, maybe_fatal) (delete_tty) [HAVE_ANDROID]: Exclude or turn these functions into vestiges. (Fsuspend_tty, Fresume_tty): Call `emacs_fclose' and always signal on Android. (Fresume_tty): Call `emacs_fdopen'. (Ftty__set_output_buffer_size) [HAVE_ANDROID]: Remove this function. (encode_terminal_code): Replace with a stub. (init_tty, delete_tty, maybe_fatal): Call `emacs_fclose'. (syms_of_term): Remove most unnecessary code on Android. <system_uses_terminfo>: Always set this option on Android. * src/sysdep.c (init_standard_fds): Call emacs_fopen. (reset_sigio, widen_foreground_group): Define out on Android. (reset_sys_modes): Don't call either function on Android. (init_sigbus, handle_sigbus): New functions. (init_signals): Don't add user signals on Android. Register signal handlers for SIGBUS, and refrain from handling SIGSEGV. (emacs_fstatat): Wrap android_fstatat on Android. (sys_fstat, sys_faccessat): New function. (emacs_openat): Exclude this function when building libemacs.so. (emacs_open, emacs_open_noquit, emacs_fopen, emacs_close): Wrap functions defined in the Android filesystem emulation code. (emacs_fdopen, emacs_fclose, emacs_unlink, emacs_symlink) (emacs_rmdir, emacs_mkdir, emacs_renameat_noreplace, emacs_rename) (emacs_fchmodat): New wrappers for more of those functions. (close_output_streams): Placate the file descriptor sanitizer that's included with android. * src/sound.c (Fplay_sound_internal): Pass extra argument to openp. * src/sfntfont.h: * src/sfntfont.c: * src/sfntfont-android.c: * src/sfnt.h: * src/sfnt.c: New files. * src/scroll.c: Exclude the entire file on Android. * src/process.c: (allocate_pty): Call sys_faccessat, not faccessat. (Fmake_process): Call openp with an extra argument. (wait_reading_process_output): Call android_select. (Fprocess_send_eof): Don't call tcdrain if not present. (handle_child_signal): Write a comment describing a small, seldom encountered issue. * src/print.c (print_vectorlike): Don't print FONT_EXTRA_INDEX for font entities. * src/pdumper.c (Fdump_emacs_portable): Allow dumping in interactive Emacs's on Android, as this is performed within loadup.el. (dump_discard_mem): Use madvise if posix_advise is not present. (pdumper_load): Call sys_fstat, not fstat. (syms_of_pdumper) <Vpdumper_fingerprint>: Calculate the fingerprint for this Emacs executable and store it there. * src/menu.c (have_boxes): Android has boxes. (push_submenu_start, push_submenu_end): Define on Android. (single_menu_item): Produce submenus on Android as well. (x_popup_menu_1): Call EVENT_START, in contrast to duplicating its old functionality with calls to Fcar and XCDR. (Fx_popup_menu): Update documentation to reflect that touch screen events are now accepted as POSITION. * src/marker.c (set_marker_internal): Redisplay buffers when their mark changes, enabling changes to be reported to the IME. * src/lread.c (lread_fd, lread_fd_cmp, lread_fd_p, lread_close) (lread_fstat, lread_read_quit, lread_lseek, file_stream) (file_seek, file_stream_valid_p, file_stream_close) (file_stream_invalid, getc): New macros. Define to an implementation with file descriptors and file streams on systems other than Android 2.3+, and one using Android file descriptors on those systems. (USE_ANDROID_ASSETS): Define on Android 2.3+; (file_get_char): New function. (infile, skip_dyn_bytes, skip_dyn_eof, readbyte_from_stdio) (read_filtered_event, safe_to_load_version, close_infile_unwind): Implement in terms of those macros. (close_file_unwind_android_fd): New function. (Fload): Pass extra argument to `openp' and use Android file descriptors where possible. (Flocate_file_internal): Pass extra argument to `openp'. (maybe_swap_for_eln1): Call sys_fstat, not fstat. (openp): New arg PLATFORM; if supplied and opening a platform-specific file descriptor replacement is possible, place one there. (build_load_history): Fix typos in comments. (skip_lazy_string): Implement in terms of the aformentioned macros. * src/lisp.h: Add declarations for new functions. * src/keyboard.h (reading_key_sequence): Declare here. (EVENT_START): Treat touch screen events specially by returning the posn of their touch point. * src/keyboard.c (reading_key_sequence, menu_bar_touch_id): New variables. (command_loop_1): (read_menu_command): Pass false to read_key_sequence. (read_char): Update commentary. (readable_events): If text conversion events (edits from an input method) are queued, return 1. (kbd_buffer_get_event): If text conversion events exist, carry out the edits contained within. Then, generate a Qtext_conversion event. (lispy_function_keys, FUNCTION_KEY_OFFSET): Define function key array on Android. (coords_in_tab_bar_window): New function. (make_lispy_event) <TOUCHSCREEN_BEGIN_EVENT>: Keep track of touches that fall into the confines of the tab bar, and include the tab bar item in their position lists. Moreover, retain and track the touch in C code if it's taking place within the menu bar. <TOUCHSCREEN_END_EVENT>: Likewise for the tab bar; generate menu bar events if the touch ends on a menu item and was previously singled out for tracking. <TOUCHSCREEN_UPDATE_EVENT>: Don't deliver this event if the frame is dead, or if it was identified for tracking since the only touch sequence that changed begun inside the menu bar. (handle_async_input): Call android_check_query_urgent. (handle_input_available_signal): Add memory fence. (parse_tool_bar_item): Handle `wrap' properties within tool bar items moving subsequent items onto a new row. (access_keymap_keyremap): New arguments START, END, KEYBUF. Set Qcurrent_key_remap_sequence around calls to the remap function. (keyremap_step): Pass the necessary information to access_keymap_keyremap. (restore_reading_key_sequence): New function. (read_key_sequence): Set `reading_key_sequence'. New arg DISABLE_TEXT_CONVERSION_P, which causes text conversion to be disabled as long as the key sequence is being read. Disable text conversion as well if a menu or function key prefix is read, insert imaginary prefix keys before touchscreen events within special areas of a frame. Don't insert prefix keys if input is being mocked, which transpires if the input is in actuality originating from a key translation map. (read_key_sequence_vs): New argument DISABLE_TEXT_CONVERSION. (Fread_key_sequence): New argument DISABLE_TEXT_CONVERSION. (Fopen_dribble_file): Use emacs_fclose. (head_table): Make touchscreen-begin and touchscreen-end events touchscreen events. (syms_of_keyboard) <QCwrap, Qtouchscreen, Qtext_conversion>: New symbols. <disable_inhibit_text_conversion, Vcurrent_key_remap_sequence>: New variables. * src/inotify.c (Finotify_add_watch): Detect and avoid watching special files that don't exist from the POV of inotify. * src/image.c (image_create_bitmap_from_data) (image_create_bitmap_from_file, free_bitmap_record) (prepare_image_for_display, image_clear_image_1) (image_clear_image_1, image_size_in_bytes, image_set_transform): (Create_Pixmap_From_Bitmap_Data, lookup_rgb_color) (image_to_emacs_colors, image_from_emacs_colors) (image_pixmap_draw_cross, image_disable_image): Implement on Android, reusing much of the X11 code. (matrix_identity, matrix_rotate, matrix_mirror_horizontal) (matrix_translate): New functions. (x_check_image_size, x_create_x_image_and_pixmap) (x_destroy_x_image, image_check_image_size) (image_create_x_image_and_pixmap_1, image_destroy_x_image) (gui_put_x_image, image_get_x_image, image_unget_x_image): Implement on Android. (image_find_image_fd): Return an Android file descriptor if possible. (close_android_fd): New function. (slurp_file): Accept `image_fds', defined to Android file descriptors. (xpm_load): Enable built-in XPM support on Android. (xbm_load, pbm_load, png_load_body, jpeg_load_body, gif_load) (webp_load, imagemagick_load_image, svg_load): Use image file descriptors on Android; these file descriptors may in fact represent compressed asset streams, and obviate the necessity of creating a new file descriptor for each asset image opened. (Fimage_transforms_p): Report rotate90 on Android. (image_types, syms_of_image): Enable built-in XPM support on Android. * src/fringe.c (init_fringe_bitmap): Bit swap bitmaps on Android, as on X. * src/frame.h (enum text_conversion_operation): New enumerator. (struct text_conversion_action, struct text_conversion_state): New variable. (struct frame): New fields `tool_bar_wraps_p' and `conversion'. Increase the width of `output_method'. <output_data>: Add `android' field. <wait_event_type>: Define on Android as well. (fset_menu_bar_window): Define correctly, so that it's declared on non-X builds without external menu bars. (FRAME_ANDROID_P): Define macro. (FRAME_WINDOW_P) [HAVE_ANDROID]: Define to FRAME_ANDROID_P. (FRAME_RES): New macro. (MOUSE_HL_INFO): Define without referencing tty output data on Android, which doesn't have them. * src/frame.c (Fframep): Return `android' on Android systems. (Fwindow_system): Likewise. (make_frame): Clear text conversion state and `tool_bar_wraps_p'. (Fmake_terminal_frame): Signal that Android doesn't support text terminals. (delete_frame): Reset text conversion state prior to deleting the frame. (gui_display_get_resource): Don't call the resource hook on Android. (Fx_parse_geometry): Pacify compiler warning. (make_monitor_attribute_list): Don't always use SOURCE if nil. (syms_of_frame) <Qandroid>: New symbol. <Vdefault_frame_scroll_bars>: Don't default scroll bars to an enabled state on Android. * src/fontset.c (fontset_find_font): Tackle an unusual problem. * src/font.h (struct font_entity): New field `is_android'. (PT_PER_INCH): Define to 160.00 on Android. * src/font.c (font_make_entity): New function. (font_make_entity_android): New variant that sets `is_android' to true. (font_pixel_size, font_find_for_lface, font_open_for_lface) (Ffont_face_attributes, Fopen_font): Respect the distinction between frame text and display scales. * src/fns.c (Flocale_info): Silence compiler warning. * src/filelock.c (BOOT_TIME): Undefine BOOT_TIME when building libemacs.so (get_boot_time, rename_lock_file, create_lock_file) (current_lock_owner, make_lock_file_name, unlock_file): Employ wrappers for Android filesystem operations. * src/fileio.c (emacs_fd, emacs_fd_open, emacs_fd_close) (emacs_fd_read, emacs_fd_lseek, emacs_fd_fstat, emacs_fd_valid_p): New type and macros; define them to suitable values, akin to those in lread.c (check_vfs_filename): New function. (file_access_p): Call `sys_faccessat'. (close_file_unwind_emacs_fd): New function. (fclose_unwind): Call `emacs_fclose', not fclose. (file_name_directory): Export this function. (user_homedir): If PW->pw_dir is not set and its uid is the current user, call `android_get_home_directory'. (get_homedir): Call `android_get_home_directory' if PW->pw_dir is not set. (Fcopy_file, Fmake_directory_internal, Fdelete_directory_internal) (Fdelete_file, Frename_file, Fmake_symbolic_link, Faccess_file) (file_directory_p, file_accessible_directory_p, Fset_file_modes) (Fset_file_times, Ffile_newer_than_file_p, read_non_regular) (Finsert_file_contents, write_region) (Fverify_visited_file_modtime, Fset_visited_file_modtime) (do_auto_save_unwind): Make use of Android filesystem wrappers and file descriptors where possible. (Fadd_name_to_file): Prohibit creating links to and from files residing on Android special directories. (Ffile_system_info): Avoid compilation failure on Android, where Gnulib can't find out how to implement statfs. * src/epaths.in [HAVE_ANDROID && !ANDROID_STUBIFY]: Deface this file, so Makefile cannot change the hard-coded values within. * src/emacs.c (using_utf8): Correctly initialize mbstate_t on Android. (init_cmdargs): Pass extra argument to openp. (load_pdump): When building libemacs.so, use solely the file provided on the command line or as an argument to `android_emacs_init'. (load_seccomp): Call sys_fstat, not fstat. (main, android_emacs_init): Name `main' `android_emacs_init' when building libemacs.so, and accept an argument designating the dump file. (main): Initialize text conversion and Android. Don't presume that argv is NULL terminated. (Fkill_emacs, shut_down_emacs): Properly implement RESTART on Android. (syms_of_emacs) <Vsystem_type>: Describe the possible value `android'. * src/emacs-module.c (MODULE_HANDLE_NONLOCAL_EXIT): Cease relying on GCC clean-up attribute extension. (MODULE_INTERNAL_CLEANUP): New macro. (module_make_global_ref, module_free_global_ref) (module_make_function, module_get_function_finalizer) (module_make_interactive, module_funcall, module_extract_integer) (module_extract_float, module_copy_string_contents) (module_get_user_ptr, module_set_user_ptr) (module_get_user_finalizer, module_set_user_finalizer) (module_vec_set, module_vec_size, module_process_input) (module_extract_big_integer, module_make_big_integer): Carry out necessary clean-up tasks using MODULE_HANDLE_NONLOCAL_EXIT. * src/editfns.c (Fuser_full_name): Call `android_user_full_name', as USER_FULL_NAME doesn't always work. * src/doc.c (doc_fd, doc_fd_p, doc_open, doc_read_quit) (doc_lseek): New types and macros, resembling those in lread.c. (get_doc_string, Fsnarf_documentation): Implement in terms of those macros, so as to use Android asset streams directly. * src/dispnew.c (clear_current_matrices, clear_desired_matrices) (allocate_matrices_for_window_redisplay, free_glyphs) (redraw_frame, update_frame, scrolling, update_frame_line): Disable support for text terminals when building for Android. (Fopen_termscript): Use emacs_fclose. (init_display_interactive): Set Vinitial_window_system to Qandroid, and lose if Emacs needs to create a text terminal. * src/dispextern.h (No_Cursor, Emacs_Rectangle, struct gui_box): New definitions. (struct glyph_string) <gc>: Define to the Android GC type. (HAVE_NATIVE_TRANSPHORMS): Define on Android. (struct image): New fields `ximg', `mask_img', as on X. (enum tool_bar_item_idx): New tool bar item property TOOL_BAR_ITEM_WRAP. * src/dired.c (emacs_dir, emacs_closedir, emacs_readdir): New typedef and definitions. (open_directory): Return emacs_dir; use android_opendir on Android, instead of at-funcs. (directory_files_internal_unwind): Call emacs_closedir. (read_dirent): Call emacs_readdir. (directory_files_internal, file_name_completion) (file_name_completion_dirp): Use Android wrappers for directories and files. (file_attributes): Abstain from openat on Android. * src/conf_post.h (MB_CUR_MAX): Define to REPLACEMENT_MB_CUR_MAX if necessary to counteract inept LLVM headers. * src/coding.h (from_unicode_buffer): Define if HAVE_ANDROID as well. * src/coding.c (from_unicode_buffer): Define on Android, creating a variant that understands UCS-16 extended into wchar_t. (syms_of_coding) <Qutf_16le>: Define on Android. * src/charset.c (load_charset_map_from_file): Supply extra argument to openp, and call Emacs wrappers for fdopen and fclose. * src/callproc.c (get_current_directory): Return the home directory if ENCODED is a special directory. (delete_temp_file): Call emacs_unlink in lieu of unlink. (call_process): Use openp. (emacs_spawn): Use Android executable loader binary if needed and enabled. (init_callproc): Set Vshell_file_name to /system/bin/sh if libemacs.so. (syms_of_callproc) <Vctags_program_name, Vetags_program_name, Vhexl_program_name, Vemacsclient_program_name, Vmovemail_program_name>: New variables. Define to the names of the programs they respectively stand for. * src/callint.c (Fcall_interactively): Supply new argument in calls to Fread_key_sequence and Fread_key_sequence_vector. * src/buffer.h (struct buffer) <text_conversion_style_>: New bvar. (bset_text_conversion_style): New bvar setter. * src/buffer.c (init_buffer_once): Set the text conversion style. (syms_of_buffer) <BVAR (current_buffer, text_conversion_style)>: Define new BLV. * src/androidvfs.c: * src/androidterm.h: * src/androidterm.c: * src/androidselect.c: * src/androidmenu.c: * src/androidgui.h: * src/androidfont.c: * src/androidfns.c: * src/android.h: * src/android.c: * src/android-emacs.c: * src/android-asset.h: New function. * src/alloc.c (cleanup_vector): Finalize Android font entities. (find_string_data_in_pure) [__i386__ && !__clang__]: On Android, compensate for a bug in the latest NDK GCC. (mark_pinned_symbols, android_make_lisp_symbol): Elude another bug in debuginfo generation with an almost nonsensical fix. (garbage_collect): Mark androidterm and sfntfont. (mark_frame): Mark text conversion actions and info. * src/Makefile.in (XCONFIGURE): New variable. If set, add srcdir to vpath. (hostlib): New variable, always defined to libgnu.a on the build machine. (GIF_CFLAGS, JPEG_CFLAGS, TIFF_CFLAGS, SQLITE3_CFLAGS) (LIBSELINUX_CFLAGS, ANDROID_OBJ, ANDROID_LIBS, ANDROID_LDFLAGS) (ANDROID_BUILD_CFLAGS, LIBGMP_CFLAGS): New variables. (CM_OBJ): Update commentary. (EMACS_CFLAGS): Add new compiler flags variables. (base_obj): Add ANDROID_OBJ. (SOME_MACHINE_OBJECTS): Add Android-related objects. (lisp.mk): Generate from its absolute file name. ($(lispsource)/international/charprop.el): Don't generate when building libemacs.so. ($(libsrc)/make-docfile$(EXEEXT) $(libsrc)/make-fingerprint$(EXEEXT)): Depend on libgnu.a on the build machine. (mostlyclean): Remove libemacs.so. (build-counter.c, libemacs.so, android-emacs): New targets. These targets are made from this Makefile copied to a subdirectory of `cross', and provide the Emacs library and an ancillary binary used by the Android port. * nt/mingw-cfg.site: * nt/gnulib-cfg.mk: Impede building Gnulib's vasnprintf* code. * msdos/sedlibmk.inp: * msdos/sedlibcf.inp: * msdos/sed3v2.inp: * msdos/sed1v2.inp: Fix the DJGPP build. * make-dist (possibly_non_vc_files): Add exec/configure and exec/config.h.in. * m4/ndk-build.m4: New file. * m4/getline.m4: * m4/getdelim.m4: * m4/asm-underscore.m4: Update from Gnulib. * lisp/wid-edit.el (widget-event-point): Treat touch screen events correctly. (widget-keymap): Map touchscreen-begin to widget-button-click. (widget-event-start): New function. (widget-button--check-and-call-button): (widget-button-click): Behave correctly when confronted by touch screen events. * lisp/version.el (android-read-build-system) (android_read_build_time): New functions. (emacs-build-system, emacs-repository-version-android) (emacs-repository-get-version): (emacs-repository-get-branch): Implement properly on Android, by reading a file generated during the packaging process. * lisp/touch-screen.el: New file, supplying support for translating raw touch screen events into gestures. * lisp/tool-bar.el (secondary-tool-bar-map): New defvar. (tool-bar--cache-key, tool-bar--secondary-cache-key): Make defsubsts. (tool-bar--flush-key): Flush caches for the secondary tool bar as well. (tool-bar-make-keymap, tool-bar-make-keymap-1): Append the secondary tool bar map below the primary tool bar map. (modifier-bar-modifier-list): New variable. (tool-bar-apply-modifiers, modifier-bar-button) (tool-bar-event-apply-alt-modifier) (tool-bar-event-apply-super-modifier) (tool-bar-event-apply-hyper-modifier) (tool-bar-event-apply-shift-modifier) (tool-bar-event-apply-control-modifier) (tool-bar-event-apply-meta-modifier, modifier-bar-available-p) (modifier-bar-mode): New functions. * lisp/textmodes/text-mode.el (text-mode): Set text-conversion-style to t. * lisp/textmodes/reftex-global.el (reftex-create-tags-file): Use etags-program-name to provide the name of the etags program. * lisp/textmodes/conf-mode.el (conf-mode-initialize): Enable text conversion. * lisp/textmodes/artist.el (artist-figlet-get-font-list): Use /system/bin/sh on Android. * lisp/term/android-win.el: New file. * lisp/term.el (term-mode): Always display the on screen keyboard. (term-exec-1): Use /system/bin/sh on Android. * lisp/tab-line.el (tab-line-tab-map) (tab-line-new-tab) (tab-line-select-tab) (tab-line-close-tab) (tab-line-track-tap) (tab-line-event-start): Improve support for touch screen events. * lisp/tab-bar.el (tab-bar-mouse-context-menu): (tab-bar-map): Likewise. (tab-bar-handle-timeout, tab-bar-touchscreen-begin): New functions. * lisp/subr.el (event-start): Don't return nonsense if EVENT is a touchscreen event. (event-end): Likewise. (read-key): Disable text conversion within read-key-sequence-vector. (read-char-choice-with-read-key): Display the on screen keyboard. (read-char-from-minibuffer): Disable text conversion. (use-dialog-box-p): Prefer dialog boxes on Android. (y-or-n-p): Disable text conversion properly under all three modes of operation. * lisp/startup.el (android-fonts-enumerated): New variable. (normal-top-level): Load system fonts on Android. * lisp/speedbar.el (speedbar-fetch-etags-command): Use etags-program-name instead of hard-coding `etags'. * lisp/simple.el (normal-erase-is-backspace-setup-frame): Return true on Android. (event-apply-modifier): Correctly apply Shift and Control modifiers to keys with other modifiers. (undo-auto-amalgamate): Mention analyze-text-conversion wrt being an amalgamating command. * lisp/shell.el (shell--command-completion-data): Don't lose if PATH contains an inaccessible directory. * lisp/progmodes/prog-mode.el (prog-mode): Enable text conversion. * lisp/progmodes/cperl-mode.el (cperl-etags): Don't hard-code etags, employ etags-program-name instead. * lisp/progmodes/cc-mode.el (c-initialize-cc-mode): Initialize text conversion hook. * lisp/progmodes/cc-cmds.el (c-post-text-conversion): New function. Do electric characters. * lisp/play/gamegrid.el (gamegrid-setup-default-font): Don't crash if the display resolution is too high. * lisp/play/dunnet.el (text-conversion-style): * lisp/play/doctor.el (doctor-mode): Enable text conversion. * lisp/pixel-scroll.el (pixel-scroll-precision-scroll-down-page) (pixel-scroll-precision-scroll-Up-page): Make autoloads. * lisp/org/org-ctags.el (org-ctags-path-to-ctags): Use ctags-program-name, not ctags. * lisp/obsolete/terminal.el (terminal-emulator): Start /system/bin/sh, not /bin/sh. * lisp/net/tramp.el (tramp-encoding-shell): Use /system/bin/sh on Android. * lisp/net/eww.el (eww-form-submit, eww-form-file) (eww-form-checkbox, eww-form-select): Define these faces on Android as well. * lisp/net/browse-url.el (browse-url-default-browser) (browse-url--browser-defcustom-type): Specify on Android. (browse-url-android-share, browse-url-default-android-browser): New option and function. * lisp/mwheel.el (mouse-wheel-down-event, mouse-wheel-up-event) (mouse-wheel-left-event, mouse-wheel-right-event): Define suitably on Android. * lisp/mouse.el (minor-mode-menu-from-indicator): New argument EVENT. Use it for positioning the menu. (mouse-minor-mode-menu): Pass EVENT to that function. * lisp/minibuffer.el (clear-minibuffer-message): Don't clear the message if `touch-screen-preview-select' may be underway. (minibuffer-mode): Enable text conversion. (minibuffer-setup-on-screen-keyboard) (minibuffer-exit-on-screen-keyboard): New functions. * lisp/menu-bar.el (menu-bar-close-window): New option. (menu-bar-edit-menu): Bind execute-extended-command to a menu item. (kill-this-buffer, kill-this-buffer-enabled-p): Respect menu-bar-close-window. * lisp/mail/rmail.el (rmail-autodetect, rmail-insert-inbox-text): Don't hard-code the name of movemail; rather, use movemail-program-name. * lisp/mail/emacsbug.el (emacs-build-description): Insert the Android version and manufacturer. * lisp/ls-lisp.el (ls-lisp-use-insert-directory-program): Default to off on Android. * lisp/loadup.el: Set load-list to empty load list after startup; dump the first time Emacs starts, and load Android related miscellanea. * lisp/isearch.el (isearch-text-conversion-style): New variable. (isearch-mode, isearch-done): Display the OSK, then temporarily disable and restore the on screen keyboard. * lisp/international/mule-cmds.el (set-coding-system-map): Update menu definition for Android. * lisp/international/fontset.el (script-representative-chars) (setup-default-fontset): Improve detection of CJK fonts. * lisp/image/wallpaper.el: Fix compiler warning. * lisp/ielm.el (inferior-emacs-lisp-mode): Don't hard-code name of hexl, replacing that with hexl-program-name. * lisp/htmlfontify.el (hfy-etags-bin): Replace hard-coded Emacs with etags-program-name. * lisp/hexl.el (hexl-program): Replace hard-coded hexl. * lisp/help-macro.el (make-help-screen): Display the on screen keyboard and disable text conversion prior to reading options. * lisp/gnus/mail-source.el (mail-source-movemail-program): Replace hard-coded movemail with movemail-program-name. * lisp/gnus/gnus-score.el (gnus-read-char): New function. (gnus-summary-increase-score): Use a dialog box to display these options on Android. * lisp/frame.el (frame-geometry, frame-edges) (mouse-absolute-pixel-position, set-mouse-absolute-pixel-position) (frame-list-z-order, frame-restack, display-mouse-p) (display-popup-menus-p, display-graphic-p, display-symbol-keys-p) (display-screens, display-pixel-height, display-pixel-width) (display-mm-height, display-mm-width, display-backing-store) (display-save-under, display-planes, display-color-cells) (display-visual-class, display-monitor-attributes-list): Implement window system specific functions on Android. * lisp/files.el (basic-save-buffer): Allow files to exist without a parent directory. * lisp/faces.el (tool-bar): Use default definition on Android. * lisp/emacs-lisp/eldoc.el (eldoc-add-command-completions): Add touch-screen-handle-touch and analyze-text-conversion. * lisp/elec-pair.el (electric-pair-analyze-conversion): New function. * lisp/doc-view.el (doc-view-menu): Improve menu. (doc-view-tool-bar-map): Add a new tool bar for Doc View. (doc-view-new-search): New command. (doc-view-mode): Enable that new tool bar. * lisp/dired-aux.el (dired-do-chxxx, dired-do-chmod) (dired-do-print, dired-do-shell-command, dired-do-compress-to) (dired-do-create-files, dired-do-rename, dired-do-isearch) (dired-do-isearch-regexp, dired-do-search) (dired-do-query-replace-regexp, dired-do-find-regexp) (dired-vc-next-action): Disable ``click to select'' after running this command. * lisp/dired.el (dired-insert-set-properties): Attach click-to-select keymap to file names if necessary. (dired-mode-map): Bind `touchscreen-hold' to click to select mode. (dired-post-do-command): New function. (dired-do-delete): Call it. (dired-mark-for-click, dired-enable-click-to-select-mode): New functions. (dired-click-to-select-mode): New minor mode. * lisp/cus-edit.el (custom-button-mouse, custom-button-pressed) (custom-display): Define faces to their default values on Android. * lisp/comint.el (comint-mode): Enable text conversion. * lisp/cedet/semantic/db-ebrowse.el (semanticdb-create-ebrowse-database): Replace fixed ebrowse with ebrowse-program-name. * lisp/calc/calc.el (calc-mode): Display the on screen keyboard. (calc): Insist on displaying the on screen keyboard. * lisp/button.el (button-map): Bind touch screen events to push-button. (push-button): Deal with touch screen events. * lisp/bindings.el (cut, paste, cut, text-conversion): New bindings. * lisp/battery.el (battery-status-function): Use `battery-android'. (battery-android): New function. * lib/gnulib.mk.in: * lib/getline.c: * lib/getdelim.c: * lib/Makefile.in: Update from Gnulib. * lib-src/emacsclient.c (decode_options): Set `alt_display' to `android'. * lib-src/asset-directory-tool.c: New file. * lib-src/Makefile.in: Adapt for cross-compilation. * java/res/xml/preferences.xml: * java/res/values/style.xml: * java/res/values/strings.xml: * java/res/values/bool.xml: * java/res/values-v29/style.xml: * java/res/values-v24/bool.xml: * java/res/values-v19/bool.xml: * java/res/values-v14/style.xml: * java/res/values-v11/style.xml: * java/org/gnu/emacs/EmacsWindowAttachmentManager.java: * java/org/gnu/emacs/EmacsWindow.java: * java/org/gnu/emacs/EmacsView.java: * java/org/gnu/emacs/EmacsThread.java: * java/org/gnu/emacs/EmacsSurfaceView.java: * java/org/gnu/emacs/EmacsService.java: * java/org/gnu/emacs/EmacsSdk8Clipboard.java: * java/org/gnu/emacs/EmacsSdk7FontDriver.java: * java/org/gnu/emacs/EmacsSdk23FontDriver.java: * java/org/gnu/emacs/EmacsSdk11Clipboard.java: * java/org/gnu/emacs/EmacsSafThread.java: * java/org/gnu/emacs/EmacsPreferencesActivity.java: * java/org/gnu/emacs/EmacsPixmap.java: * java/org/gnu/emacs/EmacsOpenActivity.java: * java/org/gnu/emacs/EmacsNoninteractive.java: * java/org/gnu/emacs/EmacsNative.java: * java/org/gnu/emacs/EmacsMultitaskActivity.java: * java/org/gnu/emacs/EmacsLauncherPreferencesActivity.java: * java/org/gnu/emacs/EmacsInputConnection.java: * java/org/gnu/emacs/EmacsHolder.java: * java/org/gnu/emacs/EmacsHandleObject.java: * java/org/gnu/emacs/EmacsGC.java: * java/org/gnu/emacs/EmacsFontDriver.java: * java/org/gnu/emacs/EmacsFillRectangle.java: * java/org/gnu/emacs/EmacsFillPolygon.java: * java/org/gnu/emacs/EmacsDrawable.java: * java/org/gnu/emacs/EmacsDrawRectangle.java: * java/org/gnu/emacs/EmacsDrawPoint.java: * java/org/gnu/emacs/EmacsDrawLine.java: * java/org/gnu/emacs/EmacsDocumentsProvider.java: * java/org/gnu/emacs/EmacsDirectoryEntry.java: * java/org/gnu/emacs/EmacsDialogButtonLayout.java: * java/org/gnu/emacs/EmacsDialog.java: * java/org/gnu/emacs/EmacsCursor.java: * java/org/gnu/emacs/EmacsContextMenu.java: * java/org/gnu/emacs/EmacsClipboard.java: * java/org/gnu/emacs/EmacsApplication.java: * java/org/gnu/emacs/EmacsActivity.java: * java/debug.sh: * java/README: * java/Makefile.in: * java/INSTALL: * java/AndroidManifest.xml.in: * exec/trace.c: * exec/test.c: * exec/mipsfpu.h: * exec/mipsfpu.c: * exec/mipsel-user.h: * exec/loader-x86_64.s: * exec/loader-x86.s: * exec/loader-mipsel.s: * exec/loader-mips64el.s: * exec/loader-armeabi.s: * exec/loader-aarch64.s: * exec/install-sh: * exec/exec1.c: * exec/exec.h: * exec/exec.c: * exec/deps.mk: * exec/configure.ac: * exec/config.sub: * exec/config.h.in: * exec/config.guess: * exec/config-mips.m4.in: * exec/README: * exec/Makefile.in: * etc/images/last-page.xpm: New files. * etc/PROBLEMS: Expound upon problems with font instructing on Android. * etc/NEWS: Announce changes. * etc/MACHINES: Describe support for Android. * etc/DEBUG: Illustrate the steps to debug Emacs on Android. * doc/lispref/processes.texi (Subprocess Creation): * doc/lispref/os.texi (System Environment): * doc/lispref/keymaps.texi (Translation Keymaps): (Extended Menu Items): (Tool Bar): * doc/lispref/frames.texi (Frames): (Frame Layout): (Font and Color Parameters): (Pop-Up Menus): (Window System Selections): * doc/lispref/elisp.texi (Top): * doc/lispref/display.texi (Defining Faces): (Window Systems): * doc/lispref/commands.texi (Touchscreen Events): (Touchscreen Events): (Misc Events): (Key Sequence Input): * doc/emacs/windows.texi (Tab Line): * doc/emacs/input.texi: * doc/emacs/frames.texi (Tool Bars): (Tab Bars): * doc/emacs/emacs.texi (Top): * doc/emacs/dired.texi (Marks vs Flags): * doc/emacs/android.texi: * doc/emacs/Makefile.in (EMACSSOURCES): Update the documentation to properly describe changes effected. * cross/verbose.mk.android: * cross/ndk-build/ndk-resolve.mk: * cross/ndk-build/ndk-prebuilt-static-library.mk: * cross/ndk-build/ndk-prebuilt-shared-library.mk: * cross/ndk-build/ndk-clear-vars.mk: * cross/ndk-build/ndk-build.mk.in: * cross/ndk-build/ndk-build-static-library.mk: * cross/ndk-build/ndk-build-shared-library.mk: * cross/ndk-build/ndk-build-executable.mk: * cross/ndk-build/README: * cross/ndk-build/Makefile.in: * cross/langinfo.h: * cross/README: * cross/Makefile.in: New files. * configure.ac: Configure Emacs for cross-compilation on Android. * build-aux/ndk-module-extract.awk: * build-aux/ndk-build-helper.mk: * build-aux/ndk-build-helper-4.mk: * build-aux/ndk-build-helper-3.mk: * build-aux/ndk-build-helper-2.mk: * build-aux/ndk-build-helper-1.mk: * build-aux/makecounter.sh: New file. * autogen.sh: Autogen in exec as well. * admin/merge-gnulib (GNULIB_MODULES): Add getline, stpncpy and strnlen. Clean lib. * README: * Makefile.in: * INSTALL: Update for Android. * .dir-locals.el (c-mode): Add a few new types.
This commit is contained in:
commit
c71a520d1d
293 changed files with 105609 additions and 1281 deletions
|
@ -12,7 +12,7 @@
|
|||
(c-mode . ((c-file-style . "GNU")
|
||||
(c-noise-macro-names . ("INLINE" "NO_INLINE" "ATTRIBUTE_NO_SANITIZE_UNDEFINED"
|
||||
"UNINIT" "CALLBACK" "ALIGN_STACK" "ATTRIBUTE_MALLOC"
|
||||
"ATTRIBUTE_DEALLOC_FREE"))
|
||||
"ATTRIBUTE_DEALLOC_FREE" "ANDROID_EXPORT"))
|
||||
(electric-quote-comment . nil)
|
||||
(electric-quote-string . nil)
|
||||
(indent-tabs-mode . t)
|
||||
|
|
46
.gitignore
vendored
46
.gitignore
vendored
|
@ -52,6 +52,23 @@ src/config.h
|
|||
src/epaths.h
|
||||
src/emacs-module.h
|
||||
|
||||
# Built by recursive call to `configure'.
|
||||
*.android
|
||||
!INSTALL.android
|
||||
!verbose.mk.android
|
||||
|
||||
# Built by `javac'.
|
||||
java/install_temp/*
|
||||
java/*.apk*
|
||||
java/*.dex
|
||||
java/org/gnu/emacs/*.class
|
||||
|
||||
# Built by `aapt'.
|
||||
java/org/gnu/emacs/R.java
|
||||
|
||||
# Built by `config.status'.
|
||||
java/AndroidManifest.xml
|
||||
|
||||
# C-level sources built by 'make'.
|
||||
lib/alloca.h
|
||||
lib/assert.h
|
||||
|
@ -70,8 +87,10 @@ lib/limits.h
|
|||
lib/malloc/*.gl.h
|
||||
lib/signal.h
|
||||
lib/std*.h
|
||||
lib/math.h
|
||||
!lib/std*.in.h
|
||||
!lib/stdio-impl.h
|
||||
!lib/_Noreturn.h
|
||||
lib/string.h
|
||||
lib/sys/
|
||||
lib/time.h
|
||||
|
@ -81,6 +100,19 @@ src/globals.h
|
|||
src/lisp.mk
|
||||
src/verbose.mk
|
||||
|
||||
# Stuff built during cross compilation
|
||||
cross/lib/*
|
||||
cross/src/*
|
||||
cross/lib-src/*
|
||||
cross/sys/*
|
||||
cross/config.status
|
||||
cross/*.bak
|
||||
cross/etc/DOC
|
||||
|
||||
cross/ndk-build/Makefile
|
||||
cross/ndk-build/ndk-build.mk
|
||||
cross/ndk-build/*.o
|
||||
|
||||
# Lisp-level sources built by 'make'.
|
||||
*cus-load.el
|
||||
*loaddefs.el
|
||||
|
@ -186,6 +218,7 @@ ID
|
|||
# Executables.
|
||||
*.exe
|
||||
a.out
|
||||
lib-src/asset-directory-tool
|
||||
lib-src/be-resources
|
||||
lib-src/blessmail
|
||||
lib-src/ctags
|
||||
|
@ -208,6 +241,7 @@ nextstep/GNUstep/Emacs.base/Resources/Info-gnustep.plist
|
|||
src/bootstrap-emacs
|
||||
src/emacs
|
||||
src/emacs-[0-9]*
|
||||
src/sfnt
|
||||
src/Emacs
|
||||
src/temacs
|
||||
src/dmpstruct.h
|
||||
|
@ -338,3 +372,15 @@ lib-src/seccomp-filter-exec.pfc
|
|||
# GDB history
|
||||
.gdb_history
|
||||
_gdb_history
|
||||
|
||||
# Files ignored in exec/.
|
||||
exec/config.status
|
||||
exec/loader
|
||||
exec/test
|
||||
exec/exec1
|
||||
exec/deps/*
|
||||
exec/autom4te.cache
|
||||
exec/config.h
|
||||
exec/config-mips.m4
|
||||
exec/configure
|
||||
exec/*.s.s
|
||||
|
|
7961
ChangeLog.android
Normal file
7961
ChangeLog.android
Normal file
File diff suppressed because it is too large
Load diff
6
INSTALL
6
INSTALL
|
@ -5,9 +5,9 @@ See the end of the file for license conditions.
|
|||
|
||||
|
||||
This file contains general information on building GNU Emacs. For
|
||||
more information specific to the MS-Windows, GNUstep/macOS, and MS-DOS
|
||||
ports, also read the files nt/INSTALL, nextstep/INSTALL, and
|
||||
msdos/INSTALL.
|
||||
more information specific to the MS-Windows, GNUstep/macOS, MS-DOS,
|
||||
and Android ports, also read the files nt/INSTALL, nextstep/INSTALL,
|
||||
msdos/INSTALL, and java/INSTALL.
|
||||
|
||||
For information about building from a Git checkout (rather than an
|
||||
Emacs release), read the INSTALL.REPO file first.
|
||||
|
|
62
Makefile.in
62
Makefile.in
|
@ -106,15 +106,15 @@ top_builddir = @top_builddir@
|
|||
|
||||
FIND_DELETE = @FIND_DELETE@
|
||||
|
||||
HAVE_NATIVE_COMP = @HAVE_NATIVE_COMP@
|
||||
|
||||
USE_STARTUP_NOTIFICATION = @USE_STARTUP_NOTIFICATION@
|
||||
|
||||
HAVE_NATIVE_COMP = @HAVE_NATIVE_COMP@
|
||||
HAVE_BE_APP = @HAVE_BE_APP@
|
||||
|
||||
HAVE_PGTK = @HAVE_PGTK@
|
||||
HAVE_GSETTINGS = @HAVE_GSETTINGS@
|
||||
|
||||
ANDROID = @ANDROID@
|
||||
|
||||
# ==================== Where To Install Things ====================
|
||||
|
||||
# Location to install Emacs.app under GNUstep / macOS.
|
||||
|
@ -339,6 +339,10 @@ EMACS_PDMP = `./src/emacs${EXEEXT} --fingerprint`.pdmp
|
|||
# Subdirectories to make recursively.
|
||||
SUBDIR = $(NTDIR) lib lib-src src lisp
|
||||
|
||||
ifeq ($(ANDROID),yes)
|
||||
SUBDIR := $(SUBDIR) java
|
||||
endif
|
||||
|
||||
# The subdir makefiles created by config.status.
|
||||
SUBDIR_MAKEFILES_IN = @SUBDIR_MAKEFILES_IN@
|
||||
SUBDIR_MAKEFILES = $(patsubst ${srcdir}/%,%,${SUBDIR_MAKEFILES_IN:.in=})
|
||||
|
@ -467,20 +471,20 @@ epaths-force:
|
|||
esac; \
|
||||
done
|
||||
@(gamedir='${gamedir}'; \
|
||||
sed < ${srcdir}/src/epaths.in > epaths.h.$$$$ \
|
||||
-e 's;\(#.*PATH_LOADSEARCH\).*$$;\1 "${standardlisppath}";' \
|
||||
-e 's;\(#.*PATH_REL_LOADSEARCH\).*$$;\1 "${lispdirrel}";' \
|
||||
-e 's;\(#.*PATH_SITELOADSEARCH\).*$$;\1 "${locallisppath}";' \
|
||||
-e 's;\(#.*PATH_DUMPLOADSEARCH\).*$$;\1 "${buildlisppath}";' \
|
||||
-e '/^#define PATH_[^ ]*SEARCH /s/\([":]\):*/\1/g' \
|
||||
-e '/^#define PATH_[^ ]*SEARCH /s/:"/"/' \
|
||||
-e 's;\(#.*PATH_EXEC\).*$$;\1 "${archlibdir}";' \
|
||||
-e 's;\(#.*PATH_INFO\).*$$;\1 "${infodir}";' \
|
||||
-e 's;\(#.*PATH_DATA\).*$$;\1 "${etcdir}";' \
|
||||
-e 's;\(#.*PATH_BITMAPS\).*$$;\1 "${bitmapdir}";' \
|
||||
-e 's;\(#.*PATH_X_DEFAULTS\).*$$;\1 "${x_default_search_path}";' \
|
||||
-e 's;\(#.*PATH_GAME\).*$$;\1 $(PATH_GAME);' \
|
||||
-e 's;\(#.*PATH_DOC\).*$$;\1 "${etcdocdir}";') && \
|
||||
sed < ${srcdir}/src/epaths.in > epaths.h.$$$$ \
|
||||
-e 's;\(#define.*PATH_LOADSEARCH\).*$$;\1 "${standardlisppath}";' \
|
||||
-e 's;\(#define.*PATH_REL_LOADSEARCH\).*$$;\1 "${lispdirrel}";' \
|
||||
-e 's;\(#define.*PATH_SITELOADSEARCH\).*$$;\1 "${locallisppath}";' \
|
||||
-e 's;\(#define.*PATH_DUMPLOADSEARCH\).*$$;\1 "${buildlisppath}";' \
|
||||
-e '/^#define PATH_[^ ]*SEARCH /s/\([":]\):*/\1/g' \
|
||||
-e '/^#define PATH_[^ ]*SEARCH /s/:"/"/' \
|
||||
-e 's;\(#define.*PATH_EXEC\).*$$;\1 "${archlibdir}";' \
|
||||
-e 's;\(#define.*PATH_INFO\).*$$;\1 "${infodir}";' \
|
||||
-e 's;\(#define.*PATH_DATA\).*$$;\1 "${etcdir}";' \
|
||||
-e 's;\(#define.*PATH_BITMAPS\).*$$;\1 "${bitmapdir}";' \
|
||||
-e 's;\(#define.*PATH_X_DEFAULTS\).*$$;\1 "${x_default_search_path}";' \
|
||||
-e 's;\(#define.*PATH_GAME\).*$$;\1 $(PATH_GAME);' \
|
||||
-e 's;\(#define.*PATH_DOC\).*$$;\1 "${etcdocdir}";') && \
|
||||
${srcdir}/build-aux/move-if-change epaths.h.$$$$ src/epaths.h
|
||||
|
||||
# The w32 build needs a slightly different editing, and it uses
|
||||
|
@ -532,6 +536,12 @@ lisp: src
|
|||
lib lib-src lisp nt: Makefile
|
||||
$(MAKE) -C $@ all
|
||||
|
||||
java: lisp info
|
||||
$(MAKE) -C $@ all
|
||||
|
||||
cross: src
|
||||
$(MAKE) -C $@ all
|
||||
|
||||
trampolines: src lisp
|
||||
ifeq ($(HAVE_NATIVE_COMP),yes)
|
||||
$(MAKE) -C lisp trampolines
|
||||
|
@ -569,10 +579,13 @@ $(MAKEFILE_NAME): config.status $(srcdir)/configure \
|
|||
# Don't erase these files if make is interrupted while refreshing them.
|
||||
.PRECIOUS: Makefile config.status
|
||||
|
||||
# Note that calling config.status --recheck is insufficient on Android
|
||||
# due to the recursive calls to configure.
|
||||
|
||||
config.status: ${srcdir}/configure
|
||||
if [ -x ./config.status ]; then \
|
||||
if [ -x ./config.status ]; then \
|
||||
$(CFG) ./config.status --recheck; \
|
||||
else \
|
||||
else \
|
||||
$(CFG) $(srcdir)/configure $(CONFIGURE_FLAGS); \
|
||||
fi
|
||||
|
||||
|
@ -987,6 +1000,12 @@ endef
|
|||
mostlyclean_dirs = src oldXMenu lwlib lib lib-src nt doc/emacs doc/misc \
|
||||
doc/lispref doc/lispintro test
|
||||
|
||||
### Add the libexec directory to mostlyclean_dirs if its Makefile has
|
||||
### been created.
|
||||
ifneq ($(wildcard exec/Makefile),)
|
||||
mostlyclean_dirs := $(mostlyclean_dirs) exec
|
||||
endif
|
||||
|
||||
$(foreach dir,$(mostlyclean_dirs),$(eval $(call submake_template,$(dir),mostlyclean)))
|
||||
|
||||
mostlyclean: $(mostlyclean_dirs:=_mostlyclean)
|
||||
|
@ -999,7 +1018,8 @@ mostlyclean: $(mostlyclean_dirs:=_mostlyclean)
|
|||
### with them.
|
||||
###
|
||||
### Delete '.dvi' files here if they are not part of the distribution.
|
||||
clean_dirs = $(mostlyclean_dirs) nextstep admin/charsets admin/unidata
|
||||
clean_dirs = $(mostlyclean_dirs) java cross nextstep admin/charsets \
|
||||
admin/unidata
|
||||
|
||||
$(foreach dir,$(clean_dirs),$(eval $(call submake_template,$(dir),clean)))
|
||||
|
||||
|
@ -1081,6 +1101,8 @@ extraclean: maintainer-clean
|
|||
-[ "${srcdir}" = "." ] || \
|
||||
find ${srcdir} '(' -name '*~' -o -name '#*' ')' ${FIND_DELETE}
|
||||
-find . '(' -name '*~' -o -name '#*' ')' ${FIND_DELETE}
|
||||
-rm -f ${srcdir}/exec/config-tmp-* ${srcdir}/exec/aclocal.m4 \
|
||||
${srcdir}/src/config.in ${srcdir}/exec/configure
|
||||
|
||||
# The src subdir knows how to do the right thing
|
||||
# even when the build directory and source dir are different.
|
||||
|
|
5
README
5
README
|
@ -95,6 +95,11 @@ There are several subdirectories:
|
|||
'admin' holds files used by Emacs developers, and Unicode data files.
|
||||
'build-aux' holds auxiliary files used during the build.
|
||||
'm4' holds Autoconf macros used for generating the configure script.
|
||||
'java' holds the Java code for the Emacs port to Android.
|
||||
'cross' holds Makefiles and an additional copy of gnulib used to build
|
||||
Emacs for Android devices.
|
||||
'exec' holds the source code to several helper executables used to run
|
||||
user-installed programs on Android.
|
||||
|
||||
Building Emacs on non-Posix platforms requires tools that aren't part
|
||||
of the standard distribution of the OS. The platform-specific README
|
||||
|
|
|
@ -37,7 +37,7 @@ GNULIB_MODULES='
|
|||
fchmodat fcntl fcntl-h fdopendir file-has-acl
|
||||
filemode filename filevercmp flexmember fpieee
|
||||
free-posix fstatat fsusage fsync futimens
|
||||
getloadavg getopt-gnu getrandom gettime gettimeofday gitlog-to-changelog
|
||||
getline getloadavg getopt-gnu getrandom gettime gettimeofday gitlog-to-changelog
|
||||
ieee754-h ignore-value intprops largefile libgmp lstat
|
||||
manywarnings memmem-simple mempcpy memrchr memset_explicit
|
||||
minmax mkostemp mktime
|
||||
|
@ -45,7 +45,7 @@ GNULIB_MODULES='
|
|||
pathmax pipe2 pselect pthread_sigmask
|
||||
qcopy-acl readlink readlinkat regex
|
||||
sig2str sigdescr_np socklen stat-time std-gnu11 stdbool stdckdint stddef stdio
|
||||
stpcpy strnlen strtoimax symlink sys_stat sys_time
|
||||
stpcpy stpncpy strnlen strnlen strtoimax symlink sys_stat sys_time
|
||||
tempname time-h time_r time_rz timegm timer-time timespec-add timespec-sub
|
||||
update-copyright unlocked-io utimensat
|
||||
vla warnings year2038
|
||||
|
@ -114,6 +114,11 @@ for module in $AVOIDED_MODULES; do
|
|||
avoided_flags="$avoided_flags --avoid=$module"
|
||||
done
|
||||
|
||||
# Clean the lib directory as well.
|
||||
if [ -e "$src"/lib/Makefile ]; then
|
||||
make -C "$src"/lib maintainer-clean
|
||||
fi
|
||||
|
||||
"$gnulib_srcdir"/gnulib-tool --dir="$src" $GNULIB_TOOL_FLAGS \
|
||||
$avoided_flags $GNULIB_MODULES &&
|
||||
rm -- "$src"lib/gl_openssl.h \
|
||||
|
|
|
@ -256,6 +256,12 @@ Please report any problems with this script to bug-gnu-emacs@gnu.org .'
|
|||
## Let autoreconf figure out what, if anything, needs doing.
|
||||
## Use autoreconf's -f option in case autoreconf itself has changed.
|
||||
autoreconf -fi -I m4 || exit
|
||||
|
||||
echo "Running 'autoreconf -fi' in exec ..."
|
||||
|
||||
# Now, run autoreconf inside the exec directory to generate its
|
||||
# configure script.
|
||||
autoreconf -fi exec || exit
|
||||
fi
|
||||
|
||||
|
||||
|
|
43
build-aux/makecounter.sh
Executable file
43
build-aux/makecounter.sh
Executable file
|
@ -0,0 +1,43 @@
|
|||
#!/bin/sh
|
||||
# Generate or update a C file containing an increasing counter
|
||||
# variable.
|
||||
#
|
||||
# Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Emacs. GNU Emacs is free software: you can
|
||||
# redistribute it and/or modify it under the terms of the GNU General
|
||||
# Public License as published by the Free Software Foundation, either
|
||||
# version 3 of the License, or (at your option) any later version.
|
||||
#
|
||||
# GNU Emacs is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
set -e
|
||||
|
||||
curcount=
|
||||
if test -f "$1"; then
|
||||
curcount=`cat "$1" | grep = | cut -d= -f2 \
|
||||
| sed -e 's/;//' -e 's/ //'`
|
||||
fi
|
||||
|
||||
curcount=`expr 1 + $curcount 2>/dev/null || echo 0`
|
||||
|
||||
cat > $1 <<EOF
|
||||
/* Generated automatically by makecounter.sh. Do not edit! */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ifdef HAVE_ANDROID
|
||||
#define EXPORT __attribute__ ((visibility ("default")))
|
||||
#endif /* HAVE_ANDROID */
|
||||
|
||||
#ifdef EXPORT
|
||||
EXPORT
|
||||
#endif /* EXPORT */
|
||||
int emacs_shortlisp_counter = $curcount;
|
||||
EOF
|
112
build-aux/ndk-build-helper-1.mk
Normal file
112
build-aux/ndk-build-helper-1.mk
Normal file
|
@ -0,0 +1,112 @@
|
|||
# ndk-build-helper-1.mk -- Helper for ndk-build.m4.
|
||||
# Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
# This file is part of GNU Emacs.
|
||||
|
||||
# GNU Emacs is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# GNU Emacs is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# Print out information now defined. Important details include:
|
||||
# - list of source files to compile.
|
||||
# - module export include directories.
|
||||
# - module export CFLAGS.
|
||||
# - module export LDFLAGS.
|
||||
# - module name.
|
||||
|
||||
build_kind = shared
|
||||
NDK_SO_NAMES =
|
||||
NDK_A_NAMES =
|
||||
|
||||
# Record this module's dependencies. This information is used later
|
||||
# on to recurse over libraries.
|
||||
NDK_$(LOCAL_MODULE)_STATIC_LIBRARIES := $(LOCAL_STATIC_LIBRARIES) $(LOCAL_WHOLE_STATIC_LIBRARIES)
|
||||
NDK_$(LOCAL_MODULE)_SHARED_LIBRARIES := $(LOCAL_SHARED_LIBRARIES)
|
||||
NDK_$(LOCAL_MODULE)_EXPORT_INCLUDES := $(LOCAL_EXPORT_C_INCLUDE_DIRS) $(LOCAL_EXPORT_C_INCLUDES)
|
||||
NDK_CXX_FLAG_$(LOCAL_MODULE) :=
|
||||
|
||||
$(info Building $(build_kind))
|
||||
$(info $(LOCAL_MODULE))
|
||||
$(info $(addprefix $(LOCAL_PATH)/,$(LOCAL_SRC_FILES) $(LOCAL_SRC_FILES$(EMACS_ABI))))
|
||||
|
||||
ifeq ($(findstring lib,$(LOCAL_MODULE)),lib)
|
||||
NDK_SO_NAMES = $(LOCAL_MODULE)_emacs.so
|
||||
else
|
||||
NDK_SO_NAMES = lib$(LOCAL_MODULE)_emacs.so
|
||||
endif
|
||||
|
||||
define add-so-name-1
|
||||
# Now recurse over this module's dependencies.
|
||||
$$(foreach module,$$(filter-out $$(SYSTEM_LIBRARIES), $$(NDK_$(1)_SHARED_LIBRARIES)),$$(eval $$(call add-so-name,$$(module))))
|
||||
$$(foreach module,$$(filter-out $$(SYSTEM_LIBRARIES), $$(NDK_$(1)_STATIC_LIBRARIES)),$$(eval $$(call add-so-name-1,$$(module))))
|
||||
endef
|
||||
|
||||
define add-so-name
|
||||
ifeq ($(findstring lib,$(1)),lib)
|
||||
NDK_SO_NAME = $(1)_emacs.so
|
||||
else
|
||||
NDK_SO_NAME = lib$(1)_emacs.so
|
||||
endif
|
||||
|
||||
ifeq ($$(findstring $$(NDK_SO_NAME),$$(NDK_SO_NAMES)),)
|
||||
NDK_SO_NAMES := $$(NDK_SO_NAMES) $$(NDK_SO_NAME)
|
||||
|
||||
# Now recurse over this module's dependencies.
|
||||
$$(foreach module,$$(filter-out $$(SYSTEM_LIBRARIES), $$(NDK_$(1)_SHARED_LIBRARIES)),$$(eval $$(call add-so-name,$$(module))))
|
||||
|
||||
# Recurse over static library dependencies of this shared library.
|
||||
$$(foreach module,$$(filter-out $$(SYSTEM_LIBRARIES), $$(NDK_$(1)_STATIC_LIBRARIES) $$(NDK_$(1)_WHOLE_LIBRARIES)),$$(eval $$(call add-so-name-1,$$(module))))
|
||||
endif
|
||||
|
||||
ifneq ($$(findstring stdc++,$$(NDK_$(1)_SHARED_LIBRARIES)),)
|
||||
NDK_CXX_FLAG_$(LOCAL_MODULE) := yes
|
||||
endif
|
||||
endef
|
||||
|
||||
# Figure out includes from dependencies as well.
|
||||
NDK_INCLUDES := $(LOCAL_EXPORT_C_INCLUDE_DIRS) $(LOCAL_EXPORT_C_INCLUDES)
|
||||
|
||||
define add-includes
|
||||
ifeq ($$(findstring $$(NDK_$(1)_EXPORT_INCLUDES),$$(NDK_INCLUDES)),)
|
||||
NDK_INCLUDES += $$(NDK_$(1)_EXPORT_INCLUDES)
|
||||
|
||||
$$(foreach module,$$(filter-out $$(SYSTEM_LIBRARIES), $$(NDK_$(1)_SHARED_LIBRARIES)) $$(NDK_$(1)_STATIC_LIBRARIES),$$(eval $$(call add-includes,$$(module))))
|
||||
|
||||
# Recurse over shared library dependencies of this static library.
|
||||
$$(foreach module,$$(filter-out $$(SYSTEM_LIBRARIES), $$(NDK_$(1)_SHARED_LIBRARIES)),$$(eval $$(call add-so-name,$$(module))))
|
||||
|
||||
# Recurse over static or shared library dependencies of this static
|
||||
# library.
|
||||
$$(foreach module,$$(filter-out $$(SYSTEM_LIBRARIES), $$(NDK_$(1)_STATIC_LIBRARIES)),$$(eval $$(call add-so-name-1,$$(module))))
|
||||
endif
|
||||
endef
|
||||
|
||||
# Resolve additional dependencies and their export includes based on
|
||||
# LOCAL_STATIC_LIBRARIES and LOCAL_SHARED_LIBRARIES. Static library
|
||||
# dependencies can be ignored while building a shared library, as they
|
||||
# will be linked in to the resulting shared object file later.
|
||||
|
||||
SYSTEM_LIBRARIES = z libz libc c libdl dl stdc++ libstdc++ log liblog android libandroid
|
||||
|
||||
$(foreach module,$(filter-out $(SYSTEM_LIBRARIES), $(LOCAL_SHARED_LIBRARIES)),$(eval $(call add-so-name,$(module))))
|
||||
$(foreach module,$(filter-out $(SYSTEM_LIBRARIES), $(LOCAL_SHARED_LIBRARIES) $(LOCAL_STATIC_LIBRARIES) $(LOCAL_WHOLE_STATIC_LIBRARIES)),$(eval $(call add-includes,$(module))))
|
||||
|
||||
ifneq ($(findstring stdc++,$(LOCAL_SHARED_LIBRARIES)),)
|
||||
NDK_CXX_FLAG_$(LOCAL_MODULE) := yes
|
||||
endif
|
||||
|
||||
$(info $(foreach dir,$(NDK_INCLUDES),-I$(dir)))
|
||||
$(info $(LOCAL_EXPORT_CFLAGS))
|
||||
|
||||
$(info $(LOCAL_EXPORT_LDFLAGS) $(abspath $(addprefix $(NDK_BUILD_DIR)/,$(NDK_A_NAMES))) -L$(abspath $(NDK_BUILD_DIR)) $(foreach soname,$(NDK_SO_NAMES),-l:$(soname)))
|
||||
$(info $(NDK_SO_NAMES))
|
||||
$(info $(NDK_CXX_FLAG_$(LOCAL_MODULE)))
|
||||
$(info End)
|
105
build-aux/ndk-build-helper-2.mk
Normal file
105
build-aux/ndk-build-helper-2.mk
Normal file
|
@ -0,0 +1,105 @@
|
|||
# ndk-build-helper-2.mk -- Helper for ndk-build.m4.
|
||||
# Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
# This file is part of GNU Emacs.
|
||||
|
||||
# GNU Emacs is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# GNU Emacs is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# Say a static library is being built
|
||||
build_kind = static
|
||||
NDK_SO_NAMES =
|
||||
NDK_A_NAMES =
|
||||
|
||||
# Record this module's dependencies. This information is used later
|
||||
# on to recurse over libraries.
|
||||
NDK_$(LOCAL_MODULE)_STATIC_LIBRARIES := $(LOCAL_STATIC_LIBRARIES) $(LOCAL_WHOLE_STATIC_LIBRARIES)
|
||||
NDK_$(LOCAL_MODULE)_SHARED_LIBRARIES := $(LOCAL_SHARED_LIBRARIES)
|
||||
NDK_$(LOCAL_MODULE)_EXPORT_INCLUDES := $(LOCAL_EXPORT_C_INCLUDE_DIRS) $(LOCAL_EXPORT_C_INCLUDES)
|
||||
NDK_CXX_FLAG_$(LOCAL_MODULE) :=
|
||||
|
||||
$(info Building $(build_kind))
|
||||
$(info $(LOCAL_MODULE))
|
||||
$(info $(addprefix $(LOCAL_PATH)/,$(LOCAL_SRC_FILES) $(LOCAL_SRC_FILES$(EMACS_ABI))))
|
||||
|
||||
ifeq ($(findstring lib,$(LOCAL_MODULE)),lib)
|
||||
NDK_A_NAMES = $(LOCAL_MODULE).a
|
||||
else
|
||||
NDK_A_NAMES = lib$(LOCAL_MODULE).a
|
||||
endif
|
||||
|
||||
define add-a-name
|
||||
ifeq ($(findstring lib,$(1)),lib)
|
||||
NDK_A_NAME = $(1).a
|
||||
else
|
||||
NDK_A_NAME = lib$(1).a
|
||||
endif
|
||||
|
||||
ifeq ($$(findstring $$(NDK_A_NAME),$$(NDK_A_NAMES)),)
|
||||
NDK_A_NAMES := $$(NDK_A_NAMES) $$(NDK_A_NAME)
|
||||
|
||||
# Now recurse over this module's dependencies.
|
||||
$$(foreach module,$$(filter-out $$(SYSTEM_LIBRARIES), $$(NDK_$(1)_STATIC_LIBRARIES)),$$(eval $$(call add-a-name,$$(module))))
|
||||
$$(foreach module,$$(filter-out $$(SYSTEM_LIBRARIES), $$(NDK_$(1)_SHARED_LIBRARIES)),$$(eval $$(call add-so-name,$$(module))))
|
||||
endif
|
||||
|
||||
ifneq ($$(findstring stdc++,$$(NDK_$(1)_SHARED_LIBRARIES)),)
|
||||
NDK_CXX_FLAG_$(LOCAL_MODULE) := yes
|
||||
endif
|
||||
endef
|
||||
|
||||
define add-so-name
|
||||
ifeq ($(findstring lib,$(1)),lib)
|
||||
NDK_SO_NAME = $(1)_emacs.so
|
||||
else
|
||||
NDK_SO_NAME = lib$(1)_emacs.so
|
||||
endif
|
||||
|
||||
ifeq ($$(NDK_SO_NAMES:$$(NDK_SO_NAME)=),$$(NDK_SO_NAMES))
|
||||
NDK_SO_NAMES := $$(NDK_SO_NAMES) $$(NDK_SO_NAME)
|
||||
|
||||
# Now recurse over this module's dependencies.
|
||||
$$(foreach module,$$(filter-out $$(SYSTEM_LIBRARIES), $$(NDK_$(1)_STATIC_LIBRARIES)),$$(eval $$(call add-a-name,$$(module))))
|
||||
$$(foreach module,$$(filter-out $$(SYSTEM_LIBRARIES), $$(NDK_$(1)_SHARED_LIBRARIES)),$$(eval $$(call add-so-name,$$(module))))
|
||||
endif
|
||||
endef
|
||||
|
||||
# Figure out includes from dependencies as well.
|
||||
NDK_INCLUDES := $(LOCAL_EXPORT_C_INCLUDE_DIRS) $(LOCAL_EXPORT_C_INCLUDES)
|
||||
|
||||
define add-includes
|
||||
ifeq ($$(findstring $$(NDK_$(1)_EXPORT_INCLUDES),$$(NDK_INCLUDES)),)
|
||||
NDK_INCLUDES += $$(NDK_$(1)_EXPORT_INCLUDES)
|
||||
|
||||
$$(foreach module,$$(filter-out $$(SYSTEM_LIBRARIES), $$(NDK_$(1)_SHARED_LIBRARIES)) $$(NDK_$(1)_STATIC_LIBRARIES),$$(eval $$(call add-includes,$$(module))))
|
||||
endif
|
||||
endef
|
||||
|
||||
# Resolve additional dependencies based on LOCAL_STATIC_LIBRARIES and
|
||||
# LOCAL_SHARED_LIBRARIES.
|
||||
|
||||
SYSTEM_LIBRARIES = z libz libc c libdl dl libstdc++ stdc++ log liblog android libandroid
|
||||
|
||||
$(foreach module,$(filter-out $(SYSTEM_LIBRARIES), $(LOCAL_STATIC_LIBRARIES) $(LOCAL_WHOLE_STATIC_LIBRARIES)),$(eval $(call add-a-name,$(module))))
|
||||
$(foreach module,$(filter-out $(SYSTEM_LIBRARIES), $(LOCAL_SHARED_LIBRARIES)),$(eval $(call add-so-name,$(module))))
|
||||
$(foreach module,$(filter-out $(SYSTEM_LIBRARIES), $(LOCAL_SHARED_LIBRARIES) $(LOCAL_STATIC_LIBRARIES) $(LOCAL_WHOLE_LIBRARIES)),$(eval $(call add-includes,$(module))))
|
||||
|
||||
ifneq ($(findstring stdc++,$(LOCAL_SHARED_LIBRARIES)),)
|
||||
NDK_CXX_FLAG_$(LOCAL_MODULE) := yes
|
||||
endif
|
||||
|
||||
$(info $(foreach dir,$(NDK_INCLUDES),-I$(dir)))
|
||||
$(info $(LOCAL_EXPORT_CFLAGS))
|
||||
$(info $(LOCAL_EXPORT_LDFLAGS) $(abspath $(addprefix $(NDK_BUILD_DIR)/,$(NDK_A_NAMES))) $(and $(NDK_SO_NAMES), -L$(abspath $(NDK_BUILD_DIR)) $(foreach soname,$(NDK_SO_NAMES),-l:$(soname))))
|
||||
$(info $(NDK_A_NAMES) $(NDK_SO_NAMES))
|
||||
$(info $(NDK_CXX_FLAG_$(LOCAL_MODULE)))
|
||||
$(info End)
|
28
build-aux/ndk-build-helper-3.mk
Normal file
28
build-aux/ndk-build-helper-3.mk
Normal file
|
@ -0,0 +1,28 @@
|
|||
# ndk-build-helper-3.mk -- Helper for ndk-build.m4.
|
||||
# Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
# This file is part of GNU Emacs.
|
||||
|
||||
# GNU Emacs is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# GNU Emacs is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# Say a static library is being built
|
||||
build_kind = executable
|
||||
|
||||
$(info Building $(build_kind))
|
||||
$(info $(LOCAL_MODULE))
|
||||
$(info $(addprefix $(ANDROID_MODULE_DIRECTORY),$(LOCAL_SRC_FILES) $(LOCAL_SRC_FILES$(EMACS_ABI))))
|
||||
|
||||
$(info $(foreach dir,$(LOCAL_EXPORT_C_INCLUDE_DIRS) $(LOCAL_EXPORT_C_INCLUDES),-I$(dir)))
|
||||
$(info $(LOCAL_EXPORT_CFLAGS))
|
||||
$(info $(LOCAL_EXPORT_LDFLAGS))
|
||||
$(info End)
|
39
build-aux/ndk-build-helper-4.mk
Normal file
39
build-aux/ndk-build-helper-4.mk
Normal file
|
@ -0,0 +1,39 @@
|
|||
# Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
# This file is part of GNU Emacs.
|
||||
|
||||
# GNU Emacs is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# GNU Emacs is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
undefine LOCAL_MODULE
|
||||
undefine LOCAL_MODULE_FILENAME
|
||||
undefine LOCAL_SRC_FILES
|
||||
undefine LOCAL_CPP_EXTENSION
|
||||
undefine LOCAL_CPP_FEATURES
|
||||
undefine LOCAL_C_INCLUDES
|
||||
undefine LOCAL_CFLAGS
|
||||
undefine LOCAL_CPPFLAGS
|
||||
undefine LOCAL_STATIC_LIBRARIES
|
||||
undefine LOCAL_SHARED_LIBRARIES
|
||||
undefine LOCAL_WHOLE_STATIC_LIBRARIES
|
||||
undefine LOCAL_LDLIBS
|
||||
undefine LOCAL_LDFLAGS
|
||||
undefine LOCAL_ALLOW_UNDEFINED_SYMBOLS
|
||||
undefine LOCAL_ARM_MODE
|
||||
undefine LOCAL_ARM_NEON
|
||||
undefine LOCAL_DISABLE_FORMAT_STRING_CHECKS
|
||||
undefine LOCAL_EXPORT_CFLAGS
|
||||
undefine LOCAL_EXPORT_CPPFLAGS
|
||||
undefine LOCAL_EXPORT_C_INCLUDES
|
||||
undefine LOCAL_EXPORT_C_INCLUDE_DIRS
|
||||
undefine LOCAL_EXPORT_LDFLAGS
|
||||
undefine LOCAL_EXPORT_LDLIBS
|
81
build-aux/ndk-build-helper.mk
Normal file
81
build-aux/ndk-build-helper.mk
Normal file
|
@ -0,0 +1,81 @@
|
|||
# ndk-build-helper.mk -- Helper for ndk-build.m4.
|
||||
# Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
# This file is part of GNU Emacs.
|
||||
|
||||
# GNU Emacs is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# GNU Emacs is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# This Makefile sets up enough to parse an Android-style Android.mk
|
||||
# file and return useful information about its contents.
|
||||
|
||||
# See the text under ``NDK BUILD SYSTEM IMPLEMENTATION'' in
|
||||
# cross/ndk-build/README for more details.
|
||||
|
||||
# TARGET_ARCH_ABI is the ABI that is being built for.
|
||||
TARGET_ARCH_ABI := $(EMACS_ABI)
|
||||
|
||||
# TARGET_ARCH is the architecture that is being built for.
|
||||
TARGET_ARCH := $(NDK_BUILD_ARCH)
|
||||
|
||||
# NDK_LAST_MAKEFILE is the last Makefile that was included.
|
||||
NDK_LAST_MAKEFILE = $(lastword $(filter %Android.mk,$(MAKEFILE_LIST)))
|
||||
|
||||
# local-makefile is the current Makefile being loaded.
|
||||
local-makefile = $(NDK_LAST_MAKEFILE)
|
||||
|
||||
# Make NDK_BUILD_DIR absolute.
|
||||
NDK_BUILD_DIR := $(absname $(NDK_BUILD_DIR))
|
||||
|
||||
# Make EMACS_SRCDIR absolute. This must be absolute, or nested
|
||||
# Android.mk files will not be able to find CLEAR_VARS.
|
||||
EMACS_SRCDIR := $(absname $(EMACS_SRCDIR))
|
||||
|
||||
# my-dir is a function that returns the Android module directory. If
|
||||
# no Android.mk has been loaded, use ANDROID_MODULE_DIRECTORY.
|
||||
my-dir = $(or $(and $(local-makefile),$(dir $(local-makefile))),$(ANDROID_MODULE_DIRECTORY))
|
||||
|
||||
# Return all Android.mk files under the first arg.
|
||||
all-makefiles-under = $(wildcard $(1)/*/Android.mk)
|
||||
|
||||
# Return all Android.mk files in subdirectories of this Makefile's
|
||||
# location.
|
||||
all-subdir-makefiles = $(call all-makefiles-under,$(call my-dir))
|
||||
|
||||
# These functions are not implemented.
|
||||
parent-makefile =
|
||||
grand-parent-makefile =
|
||||
|
||||
NDK_IMPORTS :=
|
||||
|
||||
# Add the specified module (arg 1) to NDK_IMPORTS.
|
||||
import-module = $(eval NDK_IMPORTS += $(1))
|
||||
|
||||
# Print out module information every time BUILD_SHARED_LIBRARY is
|
||||
# called.
|
||||
|
||||
BUILD_SHARED_LIBRARY=$(BUILD_AUXDIR)ndk-build-helper-1.mk
|
||||
BUILD_STATIC_LIBRARY=$(BUILD_AUXDIR)ndk-build-helper-2.mk
|
||||
BUILD_EXECUTABLE=$(BUILD_AUXDIR)ndk-build-helper-3.mk
|
||||
CLEAR_VARS=$(BUILD_AUXDIR)ndk-build-helper-4.mk
|
||||
|
||||
# Now include Android.mk.
|
||||
|
||||
include $(ANDROID_MAKEFILE)
|
||||
|
||||
# Finally, print out the imports.
|
||||
$(info Start Imports)
|
||||
$(info $(NDK_IMPORTS))
|
||||
$(info End Imports)
|
||||
|
||||
# Dummy target.
|
||||
all:
|
88
build-aux/ndk-module-extract.awk
Normal file
88
build-aux/ndk-module-extract.awk
Normal file
|
@ -0,0 +1,88 @@
|
|||
/^Building.+$/ {
|
||||
kind = $2
|
||||
}
|
||||
|
||||
/^Start Imports$/ {
|
||||
imports = 1
|
||||
}
|
||||
|
||||
// {
|
||||
if (imports && ++imports > 2)
|
||||
{
|
||||
if (!match ($0, /^End Imports$/))
|
||||
makefile_imports = makefile_imports " " $0
|
||||
}
|
||||
else if (!match ($0, /^End$/) && !match ($0, /^Building.+$/))
|
||||
{
|
||||
if (kind)
|
||||
{
|
||||
if (target_found)
|
||||
cxx_deps = $0
|
||||
else if (ldflags_found)
|
||||
{
|
||||
target = $0
|
||||
target_found = 1
|
||||
}
|
||||
else if (cflags_found)
|
||||
{
|
||||
ldflags = $0
|
||||
ldflags_found = 1
|
||||
}
|
||||
else if (includes_found)
|
||||
{
|
||||
cflags = $0
|
||||
cflags_found = 1
|
||||
}
|
||||
else if (src_found)
|
||||
{
|
||||
includes = $0
|
||||
includes_found = 1
|
||||
}
|
||||
else if (name_found)
|
||||
{
|
||||
src = $0
|
||||
src_found = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
name = $0
|
||||
name_found = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/^End$/ {
|
||||
if (name == MODULE && (kind == "shared" || kind == "static"))
|
||||
{
|
||||
printf "module_name=%s\n", name
|
||||
printf "module_kind=%s\n", kind
|
||||
printf "module_src=\"%s\"\n", src
|
||||
printf "module_includes=\"%s\"\n", includes
|
||||
printf "module_cflags=\"%s\"\n", cflags
|
||||
printf "module_ldflags=\"%s\"\n", ldflags
|
||||
printf "module_target=\"%s\"\n", target
|
||||
printf "module_cxx_deps=\"%s\"\n", cxx_deps
|
||||
}
|
||||
|
||||
src = ""
|
||||
name = ""
|
||||
kind = ""
|
||||
includes = ""
|
||||
cflags = ""
|
||||
ldflags = ""
|
||||
name_found = ""
|
||||
src_found = ""
|
||||
includes_found = ""
|
||||
cflags_found = ""
|
||||
ldflags_found = ""
|
||||
target_found = ""
|
||||
}
|
||||
|
||||
/^End Imports$/ {
|
||||
imports = ""
|
||||
# Strip off leading whitespace.
|
||||
gsub (/^[ \t]+/, "", makefile_imports)
|
||||
printf "module_imports=\"%s\"\n", makefile_imports
|
||||
makefile_imports = ""
|
||||
}
|
1520
configure.ac
1520
configure.ac
File diff suppressed because it is too large
Load diff
190
cross/Makefile.in
Normal file
190
cross/Makefile.in
Normal file
|
@ -0,0 +1,190 @@
|
|||
### @configure_input@
|
||||
|
||||
# Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU Emacs.
|
||||
|
||||
# GNU Emacs is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# GNU Emacs is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
top_srcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
builddir = @builddir@
|
||||
|
||||
-include $(top_builddir)/src/verbose.mk
|
||||
|
||||
# Cross-compiling Emacs for Android.
|
||||
|
||||
# The cross compiled binaries are built by having ``variant''
|
||||
# Makefiles generated at configure-time. First,
|
||||
# $(top_builddir)/src/Makefile.android,
|
||||
# $(top_builddir)/lib/Makefile.android,
|
||||
# $(top_builddir)/lib/gnulib.mk.android and
|
||||
# $(top_builddir)/lib-src/Makefile.android are copied to their usual
|
||||
# locations in this directory.
|
||||
|
||||
# N.B. that LIB_SRCDIR is actually relative to builddir, because that
|
||||
# is where the gnulib files get linked.
|
||||
|
||||
LIB_SRCDIR = $(realpath $(builddir)/lib)
|
||||
LIB_TOP_SRCDIR = $(realpath $(top_srcdir))
|
||||
|
||||
SRC_SRCDIR = $(realpath $(top_srcdir)/src)
|
||||
SRC_TOP_SRCDIR = $(realpath $(top_srcdir))
|
||||
|
||||
LIB_SRC_SRCDIR = $(realpath $(top_srcdir)/lib-src)
|
||||
LIB_SRC_TOP_SRCDIR = $(realpath $(top_src))
|
||||
|
||||
# This is a list of binaries to build and install in lib-src.
|
||||
|
||||
LIBSRC_BINARIES = lib-src/etags lib-src/ctags lib-src/emacsclient \
|
||||
lib-src/ebrowse lib-src/hexl lib-src/movemail
|
||||
|
||||
CLEAN_SUBDIRS = src lib-src lib etc
|
||||
|
||||
.PHONY: all
|
||||
all: lib/libgnu.a src/libemacs.so src/android-emacs $(LIBSRC_BINARIES)
|
||||
|
||||
# This Makefile relies on builddir and top_builddir being relative
|
||||
# paths in *.android.
|
||||
|
||||
# This file is used to tell lib/gnulib.mk when
|
||||
# $(top_builddir)/config.status changes.
|
||||
config.status: $(top_builddir)/config.status
|
||||
$(AM_V_GEN) touch config.status
|
||||
|
||||
src/verbose.mk: $(srcdir)/verbose.mk.android
|
||||
$(AM_V_SILENT) cp -f $(srcdir)/verbose.mk.android \
|
||||
src/verbose.mk
|
||||
|
||||
# Gnulib, make-fingerprint and make-docfile must be built before
|
||||
# entering any of the rules below, or they will get the Android
|
||||
# versions of many headers.
|
||||
|
||||
.PHONY: $(top_builddir)/lib/libgnu.a
|
||||
$(top_builddir)/lib/libgnu.a:
|
||||
$(MAKE) -C $(top_builddir)/lib libgnu.a
|
||||
|
||||
.PHONY: $(top_builddir)/lib-src/make-fingerprint
|
||||
$(top_builddir)/lib-src/make-fingerprint: $(top_builddir)/lib/libgnu.a
|
||||
$(MAKE) -C $(top_builddir)/lib-src make-fingerprint
|
||||
|
||||
.PHONY: $(top_builddir)/lib-src/make-docfile
|
||||
$(top_builddir)/lib-src/make-docfile: $(top_builddir)/lib/libgnu.a
|
||||
$(MAKE) -C $(top_builddir)/lib-src make-docfile
|
||||
|
||||
PRE_BUILD_DEPS=$(top_builddir)/lib/libgnu.a \
|
||||
$(top_builddir)/lib-src/make-fingerprint \
|
||||
$(top_builddir)/lib-src/make-docfile
|
||||
|
||||
lib/config.h: $(top_builddir)/src/config.h.android
|
||||
$(AM_V_GEN) cp -f -p $(top_builddir)/src/config.h.android \
|
||||
lib/config.h
|
||||
|
||||
lib-src/config.h: $(top_builddir)/src/config.h.android
|
||||
$(AM_V_GEN) cp -f -p $(top_builddir)/src/config.h.android \
|
||||
lib-src/config.h
|
||||
|
||||
# Figure out where build-aux is.
|
||||
# Then, replace the build-aux directory with its actual location,
|
||||
# in case MKDIR_P points there.
|
||||
|
||||
relative_buildaux_dir := $(subst /,\/,$(top_srcdir)/build-aux)
|
||||
|
||||
lib/gnulib.mk: $(top_builddir)/lib/gnulib.mk.android
|
||||
$(AM_V_GEN) \
|
||||
sed -e 's/^srcdir =.*$$/srcdir = $(subst /,\/,$(LIB_SRCDIR))/g' \
|
||||
-e 's/$(relative_buildaux_dir)/$(subst /,\/,../$(top_builddir))\/build-aux/g' \
|
||||
< $(top_builddir)/lib/gnulib.mk.android > $@
|
||||
|
||||
lib/Makefile: $(top_builddir)/lib/Makefile.android
|
||||
$(AM_V_GEN) \
|
||||
sed -e 's/^top_srcdir =.*$$/top_srcdir = $(subst /,\/,$(LIB_TOP_SRCDIR))/g' \
|
||||
-e 's/^srcdir =.*$$/srcdir = $(subst /,\/,$(LIB_SRCDIR))/g' \
|
||||
-e 's/^VPATH =.*$$/VPATH = $(subst /,\/,$(LIB_SRCDIR))/g' \
|
||||
< $(top_builddir)/lib/Makefile.android > $@
|
||||
|
||||
# What is needed to build gnulib.
|
||||
LIB_DEPS = lib/config.h lib/gnulib.mk lib/Makefile
|
||||
|
||||
.PHONY: lib/libgnu.a
|
||||
lib/libgnu.a: src/verbose.mk config.status $(LIB_DEPS) $(PRE_BUILD_DEPS)
|
||||
$(MAKE) -C lib libgnu.a
|
||||
|
||||
# Edit srcdir and top_srcdir to the right locations.
|
||||
# Edit references to ../admin/unidata to read ../../admin/unidata.
|
||||
# Next, edit libsrc to the location at top_srcdir! It is important
|
||||
# that src/Makefile uses the binaries there, instead of any
|
||||
# cross-compiled binaries at ./lib-src.
|
||||
# Edit out anything saying -I($(top_srcdir)/lib) into
|
||||
# -I$../(srcdir)/lib; that should be covered by -I$(lib)
|
||||
|
||||
src/Makefile: $(top_builddir)/src/Makefile.android
|
||||
$(AM_V_GEN) \
|
||||
sed -e 's/^srcdir =.*$$/srcdir = $(subst /,\/,$(SRC_SRCDIR))/g' \
|
||||
-e 's/^top_srcdir =.*$$/top_srcdir = $(subst /,\/,$(LIB_TOP_SRCDIR))/g' \
|
||||
-e 's/\.\.\/admin\/unidata/..\/..\/admin\/unidata/g' \
|
||||
-e 's/\.\.\/admin\/charsets/..\/..\/admin\/charsets/g' \
|
||||
-e 's/^libsrc =.*$$/libsrc = \.\.\/\.\.\/lib-src/g' \
|
||||
-e 's/libsrc =.*$$/libsrc = \.\.\/\.\.\/lib-src/g' \
|
||||
-e 's/-I\$$(top_srcdir)\/lib/-I..\/$(subst /,\/,$(srcdir))\/lib/g' \
|
||||
< $(top_builddir)/src/Makefile.android > $@
|
||||
|
||||
src/config.h: $(top_builddir)/src/config.h.android
|
||||
$(AM_V_GEN) cp -f -p $< $@
|
||||
|
||||
.PHONY: src/android-emacs src/libemacs.so
|
||||
|
||||
src/libemacs.so: src/Makefile src/config.h src/verbose.mk \
|
||||
lib/libgnu.a $(PRE_BUILD_DEPS)
|
||||
$(MAKE) -C src libemacs.so
|
||||
|
||||
src/android-emacs: src/Makefile src/config.h lib/libgnu.a \
|
||||
$(PRE_BUILD_DEPS)
|
||||
$(MAKE) -C src android-emacs
|
||||
|
||||
# Edit out SCRIPTS, it interferes with the build.
|
||||
# Make BASE_CFLAGS also include cross/lib as well as ../lib.
|
||||
|
||||
lib-src/Makefile: $(top_builddir)/lib-src/Makefile.android
|
||||
$(AM_V_GEN) \
|
||||
sed -e 's/-I\$${srcdir}\/\.\.\/lib//g' \
|
||||
-e 's/^srcdir=.*$$/srcdir = $(subst /,\/,$(LIB_SRC_SRCDIR))/g' \
|
||||
-e 's/^top_srcdir=.*$$/top_srcdir = $(subst /,\/,$(LIB_SRC_TOP_SRCDIR))/g' \
|
||||
-e 's/^SCRIPTS=.*$$/SCRIPTS=/g' \
|
||||
-e 's/-I\.\.\/lib/-I..\/lib -I..\/$(subst /,\/,$(srcdir))\/lib/g' \
|
||||
< $(top_builddir)/lib-src/Makefile.android > $@
|
||||
|
||||
.PHONY: $(LIBSRC_BINARIES)
|
||||
$(LIBSRC_BINARIES) &: src/verbose.mk $(top_builddir)/$@ lib/libgnu.a \
|
||||
lib-src/config.h lib-src/Makefile $(PRE_BUILD_DEPS)
|
||||
# Finally, go into lib-src and make everything being built
|
||||
$(MAKE) -C lib-src $(foreach bin,$(LIBSRC_BINARIES),$(notdir $(bin)))
|
||||
|
||||
.PHONY: clean maintainer-clean distclean
|
||||
clean:
|
||||
for dir in $(CLEAN_SUBDIRS); do \
|
||||
find $$dir -type f -delete; \
|
||||
done
|
||||
rm -rf lib/config.h lib-src/config.h
|
||||
# ndk-build won't have been generated in a non-Android build.
|
||||
-make -C ndk-build clean
|
||||
|
||||
maintainer-clean distclean bootstrap-clean: clean
|
||||
# Remove links created by configure.
|
||||
for dir in $(CLEAN_SUBDIRS); do \
|
||||
find $$dir -type l -delete; \
|
||||
done
|
||||
rm -rf lib/Makefile lib/gnulib.mk ndk-build/Makefile
|
||||
rm -rf ndk-build/ndk-build.mk Makefile
|
5
cross/README
Normal file
5
cross/README
Normal file
|
@ -0,0 +1,5 @@
|
|||
This directory holds Makefiles and other required assets to build an
|
||||
Emacs binary independently for another toolchain.
|
||||
|
||||
The directory ndk-build also contains an implementation of the Android
|
||||
`ndk-build' build system.
|
20
cross/langinfo.h
Normal file
20
cross/langinfo.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
/* Replacement langinfo.h file for building GNU Emacs on Android.
|
||||
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#define nl_langinfo(ignore) "ASCII"
|
144
cross/ndk-build/Makefile.in
Normal file
144
cross/ndk-build/Makefile.in
Normal file
|
@ -0,0 +1,144 @@
|
|||
### @configure_input@
|
||||
|
||||
# Copyright 2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU Emacs.
|
||||
|
||||
# GNU Emacs is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# GNU Emacs is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# ndk-build works by including a bunch of Makefiles which set
|
||||
# variables, and then having those Makefiles include another makefile
|
||||
# which actually builds targets.
|
||||
|
||||
srcdir = @srcdir@
|
||||
|
||||
# This is a list of Android.mk files which provide targets.
|
||||
NDK_BUILD_ANDROID_MK = @NDK_BUILD_ANDROID_MK@
|
||||
NDK_BUILD_ARCH = @NDK_BUILD_ARCH@
|
||||
NDK_BUILD_ABI = @NDK_BUILD_ABI@
|
||||
NDK_BUILD_SDK = @NDK_BUILD_SDK@
|
||||
NDK_BUILD_CC = @NDK_BUILD_CC@
|
||||
NDK_BUILD_CXX = @NDK_BUILD_CXX@
|
||||
NDK_BUILD_AR = @NDK_BUILD_AR@
|
||||
NDK_BUILD_NASM = @NDK_BUILD_NASM@
|
||||
NDK_BUILD_CFLAGS = @NDK_BUILD_CFLAGS@
|
||||
|
||||
# This is a list of targets to build.
|
||||
NDK_BUILD_MODULES = @NDK_BUILD_MODULES@
|
||||
|
||||
# This is set by the Android in tree build system and is used by some
|
||||
# libraries to look for the NDK. Its value is unimportant.
|
||||
NDK_ROOT = /tmp/
|
||||
|
||||
# Finally, here are rules common to Emacs.
|
||||
.PHONY: all
|
||||
all: $(NDK_BUILD_MODULES)
|
||||
|
||||
define uniqify
|
||||
$(if $1,$(firstword $1) $(call uniqify,$(filter-out $(firstword $1),$1)))
|
||||
endef
|
||||
|
||||
# Remove duplicate files.
|
||||
NDK_BUILD_ANDROID_MK := $(call uniqify,$(NDK_BUILD_ANDROID_MK))
|
||||
|
||||
# Remove duplicate modules as well. These can occur when a single
|
||||
# module imports a module and also declares it in
|
||||
# LOCAL_SHARED_LIBRARIES.
|
||||
NDK_BUILD_MODULES := $(call uniqify,$(NDK_BUILD_MODULES))
|
||||
|
||||
# Define CFLAGS for compiling C++ code; this involves removing all
|
||||
# -std=NNN options.
|
||||
NDK_BUILD_CFLAGS_CXX := $(filter-out -std=%,$(NDK_BUILD_CFLAGS))
|
||||
|
||||
define subr-1
|
||||
|
||||
# Define ndk-build functions. Many of these are identical to those in
|
||||
# build-aux/ndk-build-helper.mk.
|
||||
|
||||
# NDK_LAST_MAKEFILE is the last Makefile that was included.
|
||||
NDK_LAST_MAKEFILE = $$(lastword $$(filter %Android.mk,$$(MAKEFILE_LIST)))
|
||||
|
||||
# local-makefile is the current Makefile being loaded.
|
||||
local-makefile = $$(NDK_LAST_MAKEFILE)
|
||||
|
||||
# my-dir is a function that returns the Android module directory. If
|
||||
# no Android.mk has been loaded, use the directory of the Makefile
|
||||
# being included.
|
||||
my-dir = $$(or $$(and $$(local-makefile),$$(dir $$(local-makefile))),$(dir $(1)))
|
||||
|
||||
# Return all Android.mk files under the first arg.
|
||||
all-makefiles-under = $$(wildcard $$(1)/*/Android.mk)
|
||||
|
||||
# Return all Android.mk files in subdirectories of this Makefile's
|
||||
# location.
|
||||
all-subdir-makefiles = $$(call all-makefiles-under,$$(call my-dir))
|
||||
|
||||
# NDK-defined include variables.
|
||||
|
||||
CLEAR_VARS = $(srcdir)/ndk-clear-vars.mk
|
||||
BUILD_EXECUTABLE = $(srcdir)/ndk-build-executable.mk
|
||||
BUILD_SHARED_LIBRARY = $(srcdir)/ndk-build-shared-library.mk
|
||||
BUILD_STATIC_LIBRARY = $(srcdir)/ndk-build-static-library.mk
|
||||
PREBUILT_SHARED_LIBRARY = $(srcdir)/ndk-prebuilt-shared-library.mk
|
||||
PREBUILT_STATIC_LIBRARY = $(srcdir)/ndk-prebuilt-static-library.mk
|
||||
|
||||
# Target information variables.
|
||||
|
||||
TARGET_ARCH = $(NDK_BUILD_ARCH)
|
||||
TARGET_PLATFORM = android-$(NDK_BUILD_SDK)
|
||||
TARGET_ARCH_ABI = $(NDK_BUILD_ABI)
|
||||
TARGET_ABI = $(TARGET_PLATFORM)-$(TARGET_ABI)
|
||||
|
||||
# Module description variables. These are defined by Android.mk.
|
||||
LOCAL_PATH :=
|
||||
LOCAL_MODULE :=
|
||||
LOCAL_MODULE_FILENAME :=
|
||||
LOCAL_SRC_FILES :=
|
||||
LOCAL_CPP_EXTENSION :=
|
||||
LOCAL_CPP_FEATURES :=
|
||||
LOCAL_C_INCLUDES :=
|
||||
LOCAL_CFLAGS :=
|
||||
LOCAL_CPPFLAGS :=
|
||||
LOCAL_STATIC_LIBRARIES :=
|
||||
LOCAL_SHARED_LIBRARIES :=
|
||||
LOCAL_WHOLE_STATIC_LIBRARIES :=
|
||||
LOCAL_LDLIBS :=
|
||||
LOCAL_LDFLAGS :=
|
||||
LOCAL_ALLOW_UNDEFINED_SYMBOLS :=
|
||||
LOCAL_ARM_MODE :=
|
||||
LOCAL_ARM_NEON :=
|
||||
LOCAL_DISABLE_FORMAT_STRING_CHECKS :=
|
||||
LOCAL_EXPORT_CFLAGS :=
|
||||
LOCAL_EXPORT_CPPFLAGS :=
|
||||
LOCAL_EXPORT_C_INCLUDES :=
|
||||
LOCAL_EXPORT_LDFLAGS :=
|
||||
LOCAL_EXPORT_LDLIBS :=
|
||||
LOCAL_ASM_RULE_DEFINED :=
|
||||
LOCAL_ASM_RULE :=
|
||||
|
||||
# Now load Android.mk.
|
||||
include $(1)
|
||||
|
||||
endef
|
||||
|
||||
# Now define rules for each Android.mk file.
|
||||
$(foreach android_mk,$(NDK_BUILD_ANDROID_MK),$(eval $(call subr-1,$(android_mk))))
|
||||
|
||||
.PHONY: clean mostlyclean
|
||||
clean mostlyclean:
|
||||
rm -rf *.o *.so *.a
|
||||
|
||||
.PHONY: extraclean dist-clean maintainer-clean
|
||||
extraclean dist-clean maintainer-clean:
|
||||
rm -rf Makefile
|
353
cross/ndk-build/README
Normal file
353
cross/ndk-build/README
Normal file
|
@ -0,0 +1,353 @@
|
|||
NDK BUILD SYSTEM IMPLEMENTATION
|
||||
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
See the end of the file for license conditions.
|
||||
|
||||
Emacs implements ndk-build itself, because the version that comes with
|
||||
the Android NDK is not easy to use from another Makefile, and keeps
|
||||
accumulating incompatible changes.
|
||||
|
||||
The Emacs implementation of ndk-build consists of one m4 file:
|
||||
|
||||
m4/ndk-build.m4
|
||||
|
||||
four Makefiles in build-aux, run during configure:
|
||||
|
||||
build-aux/ndk-build-helper-1.mk
|
||||
build-aux/ndk-build-helper-2.mk
|
||||
build-aux/ndk-build-helper-3.mk
|
||||
build-aux/ndk-build-helper.mk
|
||||
|
||||
one awk script in build-awx, run during configure:
|
||||
|
||||
build-aux/ndk-module-extract.awk
|
||||
|
||||
seven Makefiles in cross/ndk-build,
|
||||
|
||||
cross/ndk-build/ndk-build-shared-library.mk
|
||||
cross/ndk-build/ndk-build-static-library.mk
|
||||
cross/ndk-build/ndk-build-executable.mk
|
||||
cross/ndk-build/ndk-clear-vars.mk
|
||||
cross/ndk-build/ndk-prebuilt-shared-library.mk
|
||||
cross/ndk-build/ndk-prebuilt-static-library.mk
|
||||
cross/ndk-build/ndk-resolve.mk
|
||||
|
||||
and finally, two more Makefiles in cross/ndk-build, generated by
|
||||
configure:
|
||||
|
||||
cross/ndk-build/Makefile (generated from cross/ndk-build/Makefile.in)
|
||||
cross/ndk-build/ndk-build.mk (generated from cross/ndk-build/ndk-build.mk.in)
|
||||
|
||||
m4/ndk-build.m4 is a collection of macros which are used by the
|
||||
configure script to set up the ndk-build system, look for modules, add
|
||||
the appropriate options to LIBS and CFLAGS, and generate the Makefiles
|
||||
necessary to build the rest of Emacs.
|
||||
|
||||
Immediately after determining the list of directories in which to look
|
||||
for ``Android.mk'' files, the version and type of Android system being
|
||||
built for, configure calls:
|
||||
|
||||
ndk_INIT([$android_abi], [$ANDROID_SDK], [cross/ndk-build])
|
||||
|
||||
This expands to a sequence of shell script that enumerates all of the
|
||||
Android.mk files specified in "$with_ndk_path", sets up some shell
|
||||
functions used by the rest of the ndk-build code run by the configure
|
||||
script, and teaches the ndk-build system that the Makefiles to be
|
||||
generated are found in the directory "cross/ndk-build/Makefile".
|
||||
|
||||
When configure is cross-compiling for Android, the macro
|
||||
EMACS_CHECK_MODULES will expand to the macro ndk_CHECK_MODULES,
|
||||
instead of pkg-config.m4's PKG_CHECK_MODULES. Thus, the following
|
||||
code:
|
||||
|
||||
EMACS_CHECK_MODULES([PNG], [libpng >= 1.0.0])
|
||||
|
||||
will actually expand to:
|
||||
|
||||
ndk_CHECK_MODULES([PNG], [libpng >= 1.0.0], [HAVE_PNG=yes],
|
||||
[HAVE_PNG=no])
|
||||
|
||||
which in turn expands to a sequence shell script that first invokes:
|
||||
|
||||
make -f build-aux/ndk-build-helper.mk
|
||||
|
||||
for each ``Android.mk'' file found by ndk_INIT, with the following
|
||||
variables given to Make:
|
||||
|
||||
EMACS_SRCDIR=. # the source directory (in which configure is running)
|
||||
BUILD_AUXDIR=$ndk_AUX_DIR # the build-aux directory
|
||||
EMACS_ABI=$ndk_ABI # this is the $android_abi given to ndk_INIT
|
||||
ANDROID_MAKEFILE="/opt/android/libpng/Android.mk"
|
||||
ANDROID_MODULE_DIRECTORY="/opt/android/libpng"
|
||||
NDK_BUILD_DIR="$ndk_DIR" # this is the directory given as to ndk_INIT
|
||||
|
||||
build-aux/ndk-build-helper.mk will then evaluate the contents
|
||||
$(ANDROID_MAKEFILE), the ``Android.mk'' file, for the first time. The
|
||||
purpose of this evaluation is to establish a list of packages (or
|
||||
modules) provided by the ``Android.mk'' file, and the corresponding
|
||||
Makefile targets and compiler and linker flags required to build and
|
||||
link to those tagets.
|
||||
|
||||
Before doing so, build-aux/ndk-build-helper.mk will define several
|
||||
variables and functions required by all ``Android.mk'' files. The
|
||||
most important of these are:
|
||||
|
||||
my-dir # the directory containing the Android.mk file.
|
||||
BUILD_SHARED_LIBRARY # build-aux/ndk-build-helper-1.mk
|
||||
BUILD_STATIC_LIBRARY # build-aux/ndk-build-helper-2.mk
|
||||
BUILD_EXECUTABLE # build-aux/ndk-build-helper-3.mk
|
||||
CLEAR_VARS # build-aux/ndk-build-helper-4.mk
|
||||
|
||||
Then, ``Android.mk'' will include $(CLEAN_VARS), possibly other
|
||||
``Android.mk'' files, (to clear variables previously set), set several
|
||||
variables describing each module to the ndk-build system, and include
|
||||
one of $(BUILD_SHARED_LIBRARY), $(BUILD_STATIC_LIBRARY) and
|
||||
$(BUILD_EXECUTABLE).
|
||||
|
||||
Each one of those three scripts will then read from the variables set
|
||||
by ``Android.mk'', resolve dependencies, and print out some text
|
||||
describing the module to Emacs. For example, the shared library
|
||||
module "libpng" results in the following text being printed:
|
||||
|
||||
Building shared
|
||||
libpng
|
||||
/opt/android/libpng/png.c /opt/android/libpng/pngerror.c /opt/android/libpng/pngget.c /opt/android/libpng/pngmem.c /opt/android/libpng/pngpread.c /opt/android/libpng/pngread.c /opt/android/libpng/pngrio.c /opt/android/libpng/pngrtran.c /opt/android/libpng/pngrutil.c /opt/android/libpng/pngset.c /opt/android/libpng/pngtrans.c /opt/android/libpng/pngwio.c /opt/android/libpng/pngwrite.c /opt/android/libpng/pngwtran.c /opt/android/libpng/pngwutil.c
|
||||
-I/opt/android/libpng
|
||||
|
||||
-L/opt/emacs/cross/ndk-build -l:libpng_emacs.so
|
||||
libpng_emacs.so
|
||||
End
|
||||
|
||||
The output is arranged as follows:
|
||||
|
||||
- The first line consists of the word ``Building'', followed by
|
||||
either ``shared'', ``static'', or ``executable'', depending on
|
||||
what type of module being built.
|
||||
|
||||
- The second line consists of the name of the module currently being
|
||||
built.
|
||||
|
||||
- The third line consists of all of the source code files comprising
|
||||
the module.
|
||||
|
||||
- The fourth line consists of the text that has to be added to
|
||||
CFLAGS in order to find the includes associated with the module.
|
||||
|
||||
- The fifth line consists of the text that has to be added to LIBS
|
||||
in order to link with this module and all of its dependencies.
|
||||
|
||||
- The sixth line consists of the Make targets (more on this later)
|
||||
that will build the final shared object or library archive of this
|
||||
module, along with all of its dependencies.
|
||||
|
||||
- The seventh line is either empty, or the name of a dependency on
|
||||
the C++ standard library. This is used to determine whether or
|
||||
not Emacs will include the C++ standard library in the application
|
||||
package.
|
||||
|
||||
The output from Make is given to an awk script,
|
||||
build-aux/ndk-module-extract.awk. This is responsible for parsing the
|
||||
that output and filtering out modules other than what is being built:
|
||||
|
||||
awk -f build-aux/ndk-module-extract.awk MODULE=libpng
|
||||
|
||||
eventually generating this section of shell script:
|
||||
|
||||
module_name=libpng
|
||||
module_kind=shared
|
||||
module_src="/opt/android/libpng/png.c /opt/android/libpng/pngerror.c /opt/android/libpng/pngget.c /opt/android/libpng/pngmem.c /opt/android/libpng/pngpread.c /opt/android/libpng/pngread.c /opt/android/libpng/pngrio.c /opt/android/libpng/pngrtran.c /opt/android/libpng/pngrutil.c /opt/android/libpng/pngset.c /opt/android/libpng/pngtrans.c /opt/android/libpng/pngwio.c /opt/android/libpng/pngwrite.c /opt/android/libpng/pngwtran.c /opt/android/libpng/pngwutil.c"
|
||||
module_includes="-I/opt/android/libpng"
|
||||
module_cflags=""
|
||||
module_ldflags=" -L/opt/emacs/cross/ndk-build -l:libpng_emacs.so"
|
||||
module_target="libpng_emacs.so"
|
||||
module_cxx_deps=""
|
||||
module_imports=""
|
||||
|
||||
which is then evaluated by `configure'. Once the variable
|
||||
`module_name' is set, configure apends the remaining
|
||||
$(module_includes), $(module_cflags) and $(module_ldflags) to the
|
||||
module's CFLAGS and LIBS variables, and appends the list of Makefile
|
||||
targets specified to the variable NDK_BUILD_MODULES.
|
||||
|
||||
In some cases, an ``Android.mk'' file may chose to import a module
|
||||
defined in ``--with-ndk-path'', but not defined inside its own
|
||||
``Android.mk'' file. build-aux/ndk-build-helper.mk defines the
|
||||
`import-module' function to add the modules being imported to a
|
||||
variable, which is then printed out after ``ndk-build-helper.mk''
|
||||
completes. For example, libxml2 imports the ``libicucc'' module,
|
||||
which results in the following text being printed:
|
||||
|
||||
Building shared
|
||||
libxml2
|
||||
/home/oldosfan/libxml2/SAX.c /home/oldosfan/libxml2/entities.c /home/oldosfan/libxml2/encoding.c /home/oldosfan/libxml2/error.c /home/oldosfan/libxml2/parserInternals.c /home/oldosfan/libxml2/parser.c /home/oldosfan/libxml2/tree.c /home/oldosfan/libxml2/hash.c /home/oldosfan/libxml2/list.c /home/oldosfan/libxml2/xmlIO.c /home/oldosfan/libxml2/xmlmemory.c /home/oldosfan/libxml2/uri.c /home/oldosfan/libxml2/valid.c /home/oldosfan/libxml2/xlink.c /home/oldosfan/libxml2/debugXML.c /home/oldosfan/libxml2/xpath.c /home/oldosfan/libxml2/xpointer.c /home/oldosfan/libxml2/xinclude.c /home/oldosfan/libxml2/DOCBparser.c /home/oldosfan/libxml2/catalog.c /home/oldosfan/libxml2/globals.c /home/oldosfan/libxml2/threads.c /home/oldosfan/libxml2/c14n.c /home/oldosfan/libxml2/xmlstring.c /home/oldosfan/libxml2/buf.c /home/oldosfan/libxml2/xmlregexp.c /home/oldosfan/libxml2/xmlschemas.c /home/oldosfan/libxml2/xmlschemastypes.c /home/oldosfan/libxml2/xmlunicode.c /home/oldosfan/libxml2/xmlreader.c /home/oldosfan/libxml2/relaxng.c /home/oldosfan/libxml2/dict.c /home/oldosfan/libxml2/SAX2.c /home/oldosfan/libxml2/xmlwriter.c /home/oldosfan/libxml2/legacy.c /home/oldosfan/libxml2/chvalid.c /home/oldosfan/libxml2/pattern.c /home/oldosfan/libxml2/xmlsave.c /home/oldosfan/libxml2/xmlmodule.c /home/oldosfan/libxml2/schematron.c /home/oldosfan/libxml2/SAX.c /home/oldosfan/libxml2/entities.c /home/oldosfan/libxml2/encoding.c /home/oldosfan/libxml2/error.c /home/oldosfan/libxml2/parserInternals.c /home/oldosfan/libxml2/parser.c /home/oldosfan/libxml2/tree.c /home/oldosfan/libxml2/hash.c /home/oldosfan/libxml2/list.c /home/oldosfan/libxml2/xmlIO.c /home/oldosfan/libxml2/xmlmemory.c /home/oldosfan/libxml2/uri.c /home/oldosfan/libxml2/valid.c /home/oldosfan/libxml2/xlink.c /home/oldosfan/libxml2/debugXML.c /home/oldosfan/libxml2/xpath.c /home/oldosfan/libxml2/xpointer.c /home/oldosfan/libxml2/xinclude.c /home/oldosfan/libxml2/DOCBparser.c /home/oldosfan/libxml2/catalog.c /home/oldosfan/libxml2/globals.c /home/oldosfan/libxml2/threads.c /home/oldosfan/libxml2/c14n.c /home/oldosfan/libxml2/xmlstring.c /home/oldosfan/libxml2/buf.c /home/oldosfan/libxml2/xmlregexp.c /home/oldosfan/libxml2/xmlschemas.c /home/oldosfan/libxml2/xmlschemastypes.c /home/oldosfan/libxml2/xmlunicode.c /home/oldosfan/libxml2/xmlreader.c /home/oldosfan/libxml2/relaxng.c /home/oldosfan/libxml2/dict.c /home/oldosfan/libxml2/SAX2.c /home/oldosfan/libxml2/xmlwriter.c /home/oldosfan/libxml2/legacy.c /home/oldosfan/libxml2/chvalid.c /home/oldosfan/libxml2/pattern.c /home/oldosfan/libxml2/xmlsave.c /home/oldosfan/libxml2/xmlmodule.c /home/oldosfan/libxml2/schematron.c
|
||||
|
||||
|
||||
-L/home/oldosfan/emacs-dev/emacs-android/cross/ndk-build -l:libxml2_emacs.so -l:libicuuc_emacs.so
|
||||
libxml2_emacs.so libicuuc_emacs.so
|
||||
End
|
||||
Start Imports
|
||||
libicuuc
|
||||
End Imports
|
||||
|
||||
Upon encountering the ``Start Imports'' section,
|
||||
build-aux/ndk-module-extract.awk collects all imports until it
|
||||
encounters the line ``End Imports'', at which point it prints:
|
||||
|
||||
module_imports="libicuuc"
|
||||
|
||||
Then, if the list of imports is not empty, ndk_CHECK_MODULES
|
||||
additionally calls itself for each import before appending the
|
||||
module's own ``Android.mk'', ensuring that the module's imported
|
||||
dependencies are included by $ndk_DIR/Makefile before itself.
|
||||
|
||||
Finally, immediately before generating src/Makefile.android, configure
|
||||
expands:
|
||||
|
||||
ndk_CONFIG_FILES
|
||||
|
||||
to generate $ndk_DIR/Makefile and $ndk_DIR/ndk-build.mk.
|
||||
|
||||
Now, the $ndk_DIR directory is set up to build all modules upon which
|
||||
depends, and $ndk_DIR/ndk-build.mk includes a list of files required
|
||||
to link Emacs, along with the rules to chdir into $ndk_DIR in order to
|
||||
build them.
|
||||
|
||||
$ndk_DIR/ndk-build.mk is included by cross/src/Makefile
|
||||
(Makefile.android) and java/Makefile. It defines three different
|
||||
variables:
|
||||
|
||||
NDK_BUILD_MODULES the file names of all modules to be built.
|
||||
NDK_BUILD_STATIC absolute names of all library archives
|
||||
to be built.
|
||||
NDK_BUILD_SHARED absolute names of all shared libraries to
|
||||
be built.
|
||||
|
||||
and then proceeds to define rules to build each of the modules in
|
||||
$(NDK_BUILD_MODULES).
|
||||
|
||||
cross/src/Makefile arranges to have all dependencies of Emacs not
|
||||
already built built before linking ``libemacs.so'' with them.
|
||||
|
||||
java/Makefile additionally arranges to have all shared object
|
||||
dependencies built before the application package is built, which is
|
||||
normally redundant because they should have already been built before
|
||||
linking ``libemacs.so''.
|
||||
|
||||
Building the modules is performed through $ndk_DIR/Makefile, which
|
||||
contains the actual implementation of the ``ndk-build'' build system.
|
||||
First, it defines certain variables constant within the ``ndk-build''
|
||||
build system, such as the files included by ``Android.mk'' to build
|
||||
shared or static libraries, and CLEAR_VARS. The most important of
|
||||
these are:
|
||||
|
||||
CLEAR_VARS cross/ndk-build/ndk-clear-vars.mk
|
||||
BUILD_EXECUTABLE cross/ndk-build/ndk-build-executable.mk
|
||||
BUILD_SHARED_LIBRARY cross/ndk-build/ndk-build-shared-library.mk
|
||||
BUILD_STATIC_LIBRARY cross/ndk-build/ndk-build-static-library.mk
|
||||
PREBUILT_SHARED_LIBRARY cross/ndk-build/ndk-prebuilt-shared-library.mk
|
||||
PREBUILT_STATIC_LIBRARY cross/ndk-build/ndk-prebuilt-static-library.mk
|
||||
|
||||
Then, it loads each Emacs dependency's ``Android.mk'' file. For each
|
||||
module defined there, ``Android.mk'' includes $(CLEAR_VARS) to unset
|
||||
all variables specific to each module, and then includes
|
||||
$(BUILD_SHARED_LIBRARY) or $(BUILD_STATIC_LIBRARY) for each shared or
|
||||
static library module.
|
||||
|
||||
This results in cross/ndk-build/ndk-build-shared-library.mk or
|
||||
cross/ndk-build/ndk-build-static-library being included, just like the
|
||||
Makefiles in build-aux were inside the configure script.
|
||||
|
||||
Each one of those two scripts then defines rules to build all of the
|
||||
object files associated with the module, and then link or archive
|
||||
them. The name under which the module is linked is the same as the
|
||||
Make target found on the sixth line of output from
|
||||
build-aux/ndk-build-helper.mk.
|
||||
|
||||
In doing so, they both include the file ndk-resolve.mk.
|
||||
ndk-resolve.mk is expected to recursively add all of the exported
|
||||
CFLAGS and includes of any dependencies to the compiler and linker
|
||||
command lines for the module being built.
|
||||
|
||||
When building a shared library module, ndk-resolve.mk is also expected
|
||||
to define the variables NDK_LOCAL_A_NAMES_$(LOCAL_MODULE) and
|
||||
NDK_WHOLE_A_NAMES_$(LOCAL_MODULE), containing all static library
|
||||
dependencies' archive files. They are to be linked in to the
|
||||
resulting shared object file.
|
||||
|
||||
This is done by including cross/ndk-build/ndk-resolve.mk each time a
|
||||
shared or static library module is going to be built. How is this
|
||||
done?
|
||||
|
||||
First, ndk-resolve.mk saves the LOCAL_PATH, LOCAL_STATIC_LIBRARIES,
|
||||
LOCAL_SHARED_LIBRARIES, LOCAL_EXPORT_CFLAGS and
|
||||
LOCAL_EXPORT_C_INCLUDES from the module.
|
||||
|
||||
Next, ndk-resolve loops through the dependencies the module has
|
||||
specified, appending its CFLAGS and includes to the command line for
|
||||
the current module.
|
||||
|
||||
Then, that process is repeated for each such dependency which has not
|
||||
already been resolved, until all dependencies have been resolved.
|
||||
|
||||
libpng is a very simple module, providing only a single shared object
|
||||
module. This module is named libpng_emacs.so and is eventually built
|
||||
and packaged into the library directory of the Emacs application
|
||||
package. Now, let us look at a more complex module, libwebp:
|
||||
|
||||
|
||||
|
||||
When built with libwebp, Emacs depends on a single library,
|
||||
libwebpdemux. This library is named ``libwebpdemux'' on Unix systems,
|
||||
and that is the name by which it is found with pkg-config.
|
||||
|
||||
However, the library's module is only named ``webpdemux'' on Android.
|
||||
When ndk_CHECK_MODULES begins to look for a module, it first tries to
|
||||
see if its name is found in the variable `ndk_package_map', which was
|
||||
set inside ndk_INIT. In this case, it finds the following word:
|
||||
|
||||
libwebpdemux:webpdemux
|
||||
|
||||
and immediately replaces ``libwebpdemux'' with ``webpdemux''.
|
||||
|
||||
Then, it locates the ``Android.mk'' file containing a static library
|
||||
module named webpdemux and gives the output from
|
||||
build-aux/ndk-build-helper.mk to the awk script, resulting in:
|
||||
|
||||
module_name=webpdemux
|
||||
module_kind=static
|
||||
module_src="/opt/android/webp/src/demux/anim_decode.c /opt/android/webp/src/demux/demux.c"
|
||||
module_includes="-I/opt/android/webp/src"
|
||||
module_cflags=""
|
||||
module_ldflags=" cross/ndk-build/libwebpdemux.a cross/ndk-build/libwebp.a cross/ndk-build/libwebpdecoder_static.a "
|
||||
module_target="libwebpdemux.a libwebp.a libwebpdecoder_static.a"
|
||||
|
||||
The attentive reader will notice that in addition to the
|
||||
``libwebpdemux.a'' archive associated with the ``webpdemux'' library,
|
||||
Emacs has been made to link with two additional libraries. This is
|
||||
because the ``webpdemux'' module specifies a dependency on the
|
||||
``webp'' module (defined in the same Android.mk).
|
||||
build-aux/ndk-build-helper.mk resolved that dependency, noticing that
|
||||
it in turn specified another dependency on ``webpdecoder_static'',
|
||||
which in turn was added to the linker command line and list of targets
|
||||
to build.
|
||||
|
||||
As a result, all three dependencies will be built and linked to Emacs,
|
||||
instead of just the single ``webpdemux'' dependency that was
|
||||
specified.
|
||||
|
||||
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
22
cross/ndk-build/ndk-build-executable.mk
Normal file
22
cross/ndk-build/ndk-build-executable.mk
Normal file
|
@ -0,0 +1,22 @@
|
|||
# Copyright 2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU Emacs.
|
||||
|
||||
# GNU Emacs is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# GNU Emacs is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# ndk-build works by including a bunch of Makefiles which set
|
||||
# variables, and then having those Makefiles include another makefile
|
||||
# which actually builds targets.
|
||||
|
||||
# Building executables is not supported
|
171
cross/ndk-build/ndk-build-shared-library.mk
Normal file
171
cross/ndk-build/ndk-build-shared-library.mk
Normal file
|
@ -0,0 +1,171 @@
|
|||
# Copyright 2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU Emacs.
|
||||
|
||||
# GNU Emacs is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# GNU Emacs is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# ndk-build works by including a bunch of Makefiles which set
|
||||
# variables, and then having those Makefiles include another makefile
|
||||
# which actually builds targets.
|
||||
|
||||
eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1)))
|
||||
|
||||
# Objects for shared libraries are prefixed with `-shared-' in
|
||||
# addition to the name of the module, because a common practice in
|
||||
# Android.mk files written by Google is to define two modules with the
|
||||
# same name but of different types.
|
||||
objname = $(1)-shared-$(subst /,_,$(2).o)
|
||||
|
||||
# LOCAL_SRC_FILES sometimes contains absolute file names. Filter them
|
||||
# out with this function. If $(2), this is a file relative to the
|
||||
# build directory.
|
||||
maybe-absolute = $(or $(and $(2),$(1)),$(and $(wildcard $(1)),$(1)),$(LOCAL_PATH)/$(1))
|
||||
|
||||
# Here are the default flags to link shared libraries with.
|
||||
NDK_SO_DEFAULT_LDFLAGS := -lc -lm
|
||||
|
||||
define single-object-target
|
||||
|
||||
ifeq (x$(suffix $(1)),x.c)
|
||||
|
||||
$(call objname,$(LOCAL_MODULE),$(basename $(1))): $(call maybe-absolute,$(1),$(2))
|
||||
$(NDK_BUILD_CC) -c $$< -o $$@ $(NDK_CFLAGS_$(LOCAL_MODULE)) $(NDK_BUILD_CFLAGS) $(call LOCAL_C_ADDITIONAL_FLAGS,$(1))
|
||||
|
||||
else
|
||||
ifeq (x$(suffix $(1)),x.$(or $(LOCAL_CPP_EXTENSION),cpp))
|
||||
|
||||
$(call objname,$(LOCAL_MODULE),$(basename $(1))): $(call maybe-absolute,$(1))
|
||||
$(NDK_BUILD_CXX) -c $$< -o $$@ $(NDK_CFLAGS_$(LOCAL_MODULE)) $(NDK_BUILD_CFLAGS_CXX) $(NDK_CXXFLAGS_$(LOCAL_MODULE))
|
||||
|
||||
else
|
||||
ifneq ($(or $(call eq,x$(suffix $(1)),x.s),$(call eq,x$(suffix $(1)),x.S)),)
|
||||
|
||||
$(call objname,$(LOCAL_MODULE),$(basename $(1))): $(call maybe-absolute,$(1),$(2))
|
||||
$(NDK_BUILD_CC) -c $$< -o $$@ $(NDK_ASFLAGS_$(LOCAL_MODULE))
|
||||
|
||||
else
|
||||
ifneq (x$(suffix $(1)),x.asm)
|
||||
ifeq (x$(suffix $(1)),x.cc)
|
||||
|
||||
$(call objname,$(LOCAL_MODULE),$(basename $(1))): $(call maybe-absolute,$(1),$(2))
|
||||
$(NDK_BUILD_CXX) -c $$< -o $$@ $(NDK_CFLAGS_$(LOCAL_MODULE)) $(NDK_BUILD_CFLAGS_CXX) $(NDK_CXXFLAGS_$(LOCAL_MODULE))
|
||||
|
||||
else
|
||||
$$(error Unsupported suffix: $(suffix $(1)))
|
||||
endif
|
||||
else
|
||||
ifneq (x$(LOCAL_ASM_RULE_DEFINED),x)
|
||||
# Call this function to define a rule that will generate $(1) from
|
||||
# $(2), a ``.asm'' file. This is an Emacs extension.
|
||||
|
||||
$(call LOCAL_ASM_RULE,$(call objname,$(LOCAL_MODULE),$(basename $(1))),$(LOCAL_PATH)/$(strip $(1)))
|
||||
|
||||
else
|
||||
ifeq ($(findstring x86,$(NDK_BUILD_ARCH)),)
|
||||
$$(error Trying to build nasm file on non-Intel platform!)
|
||||
else
|
||||
|
||||
$(call objname,$(LOCAL_MODULE),$(basename $(1))): $(LOCAL_PATH)/$(1)
|
||||
$(NDK_BUILD_NASM) -felf$(findstring 64,$(NDK_BUILD_ARCH)) -o $$@ -i $(LOCAL_PATH) -i $$(dir $$<) $(NDK_ASFLAGS_$(LOCAL_MODULE)) $$<
|
||||
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ALL_OBJECT_FILES$(LOCAL_MODULE) += $(call objname,$(LOCAL_MODULE),$(basename $(1)))
|
||||
|
||||
endef
|
||||
|
||||
define single-neon-target
|
||||
|
||||
# Define rules for the target.
|
||||
$$(eval $$(call single-object-target,$(patsubst %.neon,%,$(1)),))
|
||||
|
||||
endef
|
||||
|
||||
# Make sure to not add a prefix to local includes that already specify
|
||||
# $(LOCAL_PATH).
|
||||
NDK_CFLAGS_$(LOCAL_MODULE) := $(addprefix -I,$(LOCAL_C_INCLUDES))
|
||||
NDK_CFLAGS_$(LOCAL_MODULE) += -fPIC -iquote $(LOCAL_PATH) $(LOCAL_EXPORT_CFLAGS) $(LOCAL_CFLAGS) $(LOCAL_CFLAGS_$(NDK_BUILD_ARCH))
|
||||
NDK_ASFLAGS_$(LOCAL_MODULE) := $(LOCAL_ASFLAGS) $(LOCAL_ASFLAGS_$(NDK_BUILD_ARCH)) $(and $(findstring clang,$(NDK_BUILD_CC)),$(LOCAL_CLANG_ASFLAGS_$(NDK_BUILD_ARCH)))
|
||||
NDK_LDFLAGS_$(LOCAL_MODULE) := $(LOCAL_LDLIBS) $(LOCAL_LDFLAGS)
|
||||
NDK_CXXFLAGS_$(LOCAL_MODULE) := $(LOCAL_CPPFLAGS) $(LOCAL_RTTI_FLAG)
|
||||
|
||||
# Now look for features in LOCAL_CPP_FEATURES and enable them.
|
||||
|
||||
ifneq ($(findstring exceptions,$(LOCAL_CPPFLAGS)),)
|
||||
NDK_CXXFLAGS_$(LOCAL_MODULE) += -fexceptions
|
||||
endif
|
||||
|
||||
ifneq ($(findstring rtti,$(LOCAL_CPPFLAGS)),)
|
||||
NDK_CXXFLAGS_$(LOCAL_MODULE) += -frtti
|
||||
endif
|
||||
|
||||
ALL_OBJECT_FILES$(LOCAL_MODULE) :=
|
||||
|
||||
ifeq ($(NDK_BUILD_ARCH)$(NDK_ARM_MODE),armarm)
|
||||
NDK_CFLAGS ::= -marm
|
||||
else
|
||||
ifeq ($(NDK_BUILD_ARCH),arm)
|
||||
NDK_CFLAGS ::= -mthumb
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(findstring lib,$(LOCAL_MODULE)),lib)
|
||||
LOCAL_MODULE_FILENAME := $(LOCAL_MODULE)_emacs
|
||||
else
|
||||
LOCAL_MODULE_FILENAME := lib$(LOCAL_MODULE)_emacs
|
||||
endif
|
||||
|
||||
# Since a shared library is being built, suffix the library with
|
||||
# _emacs. Otherwise, libraries already on the system will be found
|
||||
# first, with potentially nasty consequences.
|
||||
|
||||
LOCAL_MODULE_FILENAME := $(LOCAL_MODULE_FILENAME).so
|
||||
|
||||
# Record this module's dependencies and exported includes and CFLAGS,
|
||||
# and then add that of its dependencies.
|
||||
|
||||
include $(srcdir)/ndk-resolve.mk
|
||||
|
||||
# Then define rules to build all objects.
|
||||
ALL_SOURCE_FILES := $(LOCAL_SRC_FILES) $(LOCAL_SRC_FILES_$(NDK_BUILD_ARCH))
|
||||
|
||||
# This defines all dependencies.
|
||||
ALL_OBJECT_FILES$(LOCAL_MODULE) :=
|
||||
|
||||
# Now filter out code that is built with neon. Define rules to build
|
||||
# those separately.
|
||||
NEON_SOURCE_FILES := $(filter %.neon,$(ALL_SOURCE_FILES))
|
||||
ALL_SOURCE_FILES := $(filter-out %.neon,$(ALL_SOURCE_FILES))
|
||||
|
||||
$(foreach source,$(ALL_SOURCE_FILES),$(eval $(call single-object-target,$(source),)))
|
||||
$(foreach source,$(NEON_SOURCE_FILES),$(eval $(call single-neon-target,$(source))))
|
||||
|
||||
# Now define the rule to build the shared library. Shared libraries
|
||||
# link with all of the archive files from the static libraries on
|
||||
# which they depend, and also any shared libraries they depend on.
|
||||
|
||||
define define-module-rule
|
||||
$(LOCAL_MODULE_FILENAME): $(ALL_OBJECT_FILES$(LOCAL_MODULE)) $(NDK_LOCAL_A_NAMES_$(LOCAL_MODULE)) $(NDK_WHOLE_A_NAMES_$(LOCAL_MODULE)) $(NDK_LOCAL_SO_NAMES_$(LOCAL_MODULE))
|
||||
$(NDK_BUILD_CC) $(1) $(2) -o $$@ -shared $(NDK_LDFLAGS_$(LOCAL_MODULE)) $(NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE)) $(NDK_SO_DEFAULT_LDFLAGS) $(foreach so,$(NDK_LOCAL_SO_NAMES_$(LOCAL_MODULE)),-L $(abspath $(CURDIR)) -l:$(so))
|
||||
endef
|
||||
|
||||
NDK_WHOLE_ARCHIVE_PREFIX = -Wl,--whole-archive
|
||||
NDK_WHOLE_ARCHIVE_SUFFIX = -Wl,--no-whole-archive
|
||||
|
||||
$(eval $(call define-module-rule,$(ALL_OBJECT_FILES$(LOCAL_MODULE)) $(NDK_LOCAL_A_NAMES_$(LOCAL_MODULE)),$(and $(strip $(NDK_WHOLE_A_NAMES_$(LOCAL_MODULE))),$(NDK_WHOLE_ARCHIVE_PREFIX) $(NDK_WHOLE_A_NAMES_$(LOCAL_MODULE)) $(NDK_WHOLE_ARCHIVE_SUFFIX))))
|
142
cross/ndk-build/ndk-build-static-library.mk
Normal file
142
cross/ndk-build/ndk-build-static-library.mk
Normal file
|
@ -0,0 +1,142 @@
|
|||
# Copyright 2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU Emacs.
|
||||
|
||||
# GNU Emacs is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# GNU Emacs is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# ndk-build works by including a bunch of Makefiles which set
|
||||
# variables, and then having those Makefiles include another makefile
|
||||
# which actually builds targets.
|
||||
|
||||
eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1)))
|
||||
objname = $(1)-static-$(subst /,_,$(2).o)
|
||||
maybe-absolute = $(or $(and $(2),$(1)),$(and $(wildcard $(1)),$(1)),$(LOCAL_PATH)/$(1))
|
||||
|
||||
define single-object-target
|
||||
|
||||
ifeq (x$(suffix $(1)),x.c)
|
||||
|
||||
$(call objname,$(LOCAL_MODULE),$(basename $(1))): $(call maybe-absolute,$(1),$(2))
|
||||
$(NDK_BUILD_CC) -c $$< -o $$@ $(NDK_BUILD_CFLAGS) $(NDK_CFLAGS_$(LOCAL_MODULE)) $(call LOCAL_C_ADDITIONAL_FLAGS,$(1))
|
||||
|
||||
else
|
||||
ifeq (x$(suffix $(1)),x.$(or $(LOCAL_CPP_EXTENSION),cpp))
|
||||
|
||||
$(call objname,$(LOCAL_MODULE),$(basename $(1))): $(call maybe-absolute,$(1),$(2))
|
||||
$(NDK_BUILD_CXX) -c $$< -o $$@ $(NDK_BUILD_CFLAGS_CXX) $(NDK_CFLAGS_$(LOCAL_MODULE)) $(NDK_CXXFLAGS_$(LOCAL_MODULE))
|
||||
|
||||
else
|
||||
ifneq ($(or $(call eq,x$(suffix $(1)),x.s),$(call eq,x$(suffix $(1)),x.S)),)
|
||||
|
||||
$(call objname,$(LOCAL_MODULE),$(basename $(1))): $(call maybe-absolute,$(1),$(2))
|
||||
$(NDK_BUILD_CC) -c $$< -o $$@ $(NDK_ASFLAGS_$(LOCAL_MODULE))
|
||||
|
||||
else
|
||||
ifneq (x$(suffix $(1)),x.asm)
|
||||
ifeq (x$(suffix $(1)),x.cc)
|
||||
|
||||
$(call objname,$(LOCAL_MODULE),$(basename $(1))): $(call maybe-absolute,$(1),$(2))
|
||||
$(NDK_BUILD_CXX) -c $$< -o $$@ $(NDK_BUILD_CFLAGS_CXX) $(NDK_CFLAGS_$(LOCAL_MODULE)) $(NDK_CXXFLAGS_$(LOCAL_MODULE))
|
||||
|
||||
else
|
||||
$$(error Unsupported suffix: $(suffix $(1)))
|
||||
endif
|
||||
else
|
||||
ifneq (x$(LOCAL_ASM_RULE_DEFINED),x)
|
||||
# Call this function to define a rule that will generate $(1) from
|
||||
# $(2), a ``.asm'' file. This is an Emacs extension.
|
||||
|
||||
$(call LOCAL_ASM_RULE,$(call objname,$(LOCAL_MODULE),$(basename $(1))),$(LOCAL_PATH)/$(strip $(1)))
|
||||
|
||||
else
|
||||
ifeq ($(findstring x86,$(NDK_BUILD_ARCH)),)
|
||||
$$(error Trying to build nasm file on non-Intel platform!)
|
||||
else
|
||||
|
||||
$(call objname,$(LOCAL_MODULE),$(basename $(1))): $(call maybe-absolute,$(1),$(2))
|
||||
$(NDK_BUILD_NASM) -felf$(findstring 64,$(NDK_BUILD_ARCH)) -o $$@ -i $(LOCAL_PATH) -i $$(dir $$<) $(NDK_ASFLAGS_$(LOCAL_MODULE)) $$<
|
||||
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ALL_OBJECT_FILES$(LOCAL_MODULE) += $(call objname,$(LOCAL_MODULE),$(basename $(1)))
|
||||
endef
|
||||
|
||||
define single-neon-target
|
||||
|
||||
# Define rules for the target.
|
||||
$$(eval $$(call single-object-target,$(patsubst %.neon,%,$(1)),))
|
||||
|
||||
endef
|
||||
|
||||
NDK_CFLAGS_$(LOCAL_MODULE) := $(addprefix -I,$(LOCAL_C_INCLUDES))
|
||||
NDK_CFLAGS_$(LOCAL_MODULE) += -fPIC -iquote $(LOCAL_PATH) $(LOCAL_EXPORT_CFLAGS) $(LOCAL_CFLAGS) $(LOCAL_CFLAGS_$(NDK_BUILD_ARCH))
|
||||
NDK_ASFLAGS_$(LOCAL_MODULE) := $(LOCAL_ASFLAGS) $(LOCAL_ASFLAGS_$(NDK_BUILD_ARCH)) $(and $(findstring clang,$(NDK_BUILD_CC)),$(LOCAL_CLANG_ASFLAGS_$(NDK_BUILD_ARCH)))
|
||||
NDK_LDFLAGS_$(LOCAL_MODULE) := $(LOCAL_LDLIBS) $(LOCAL_LDFLAGS)
|
||||
NDK_CXXFLAGS_$(LOCAL_MODULE) := $(LOCAL_CPPFLAGS) $(LOCAL_RTTI_FLAG)
|
||||
ALL_OBJECT_FILES$(LOCAL_MODULE) :=
|
||||
|
||||
# Now look for features in LOCAL_CPP_FEATURES and enable them.
|
||||
|
||||
ifneq ($(findstring exceptions,$(LOCAL_CPPFLAGS)),)
|
||||
NDK_CXXFLAGS_$(LOCAL_MODULE) += -fexceptions
|
||||
endif
|
||||
|
||||
ifneq ($(findstring rtti,$(LOCAL_CPPFLAGS)),)
|
||||
NDK_CXXFLAGS_$(LOCAL_MODULE) += -frtti
|
||||
endif
|
||||
|
||||
|
||||
ifeq ($(NDK_BUILD_ARCH)$(NDK_ARM_MODE),armarm)
|
||||
NDK_CFLAGS ::= -marm
|
||||
else
|
||||
ifeq ($(NDK_BUILD_ARCH),arm)
|
||||
NDK_CFLAGS ::= -mthumb
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(findstring lib,$(LOCAL_MODULE)),lib)
|
||||
LOCAL_MODULE_FILENAME := $(LOCAL_MODULE)
|
||||
else
|
||||
LOCAL_MODULE_FILENAME := lib$(LOCAL_MODULE)
|
||||
endif
|
||||
|
||||
LOCAL_MODULE_FILENAME := $(LOCAL_MODULE_FILENAME).a
|
||||
|
||||
# Record this module's dependencies and exported includes and CFLAGS,
|
||||
# and then add that of its dependencies.
|
||||
|
||||
include $(srcdir)/ndk-resolve.mk
|
||||
|
||||
# Then define rules to build all objects.
|
||||
ALL_SOURCE_FILES := $(LOCAL_SRC_FILES) $(LOCAL_SRC_FILES_$(NDK_BUILD_ARCH))
|
||||
|
||||
# Now filter out code that is built with neon. Define rules to build
|
||||
# those separately.
|
||||
NEON_SOURCE_FILES := $(filter %.neon,$(ALL_SOURCE_FILES))
|
||||
ALL_SOURCE_FILES := $(filter-out %.neon,$(ALL_SOURCE_FILES))
|
||||
|
||||
# This defines all dependencies.
|
||||
ALL_OBJECT_FILES$(LOCAL_MODULE) =
|
||||
|
||||
$(foreach source,$(ALL_SOURCE_FILES),$(eval $(call single-object-target,$(source),)))
|
||||
$(foreach source,$(NEON_SOURCE_FILES),$(eval $(call single-neon-target,$(source),)))
|
||||
|
||||
# Now define the rule to build the library.
|
||||
$(LOCAL_MODULE_FILENAME): $(ALL_OBJECT_FILES$(LOCAL_MODULE))
|
||||
$(NDK_BUILD_AR) r $@ $^
|
68
cross/ndk-build/ndk-build.mk.in
Normal file
68
cross/ndk-build/ndk-build.mk.in
Normal file
|
@ -0,0 +1,68 @@
|
|||
### @configure_input@
|
||||
|
||||
# Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU Emacs.
|
||||
|
||||
# GNU Emacs is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# GNU Emacs is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# This file is included all over the place to get and build
|
||||
# prerequisites.
|
||||
|
||||
NDK_BUILD_MODULES = @NDK_BUILD_MODULES@
|
||||
NDK_BUILD_CXX_SHARED = @NDK_BUILD_CXX_SHARED@
|
||||
NDK_BUILD_ANY_CXX_MODULE = @NDK_BUILD_ANY_CXX_MODULE@
|
||||
NDK_BUILD_SHARED =
|
||||
NDK_BUILD_STATIC =
|
||||
|
||||
define uniqify
|
||||
$(if $1,$(firstword $1) $(call uniqify,$(filter-out $(firstword $1),$1)))
|
||||
endef
|
||||
|
||||
# Remove duplicate modules. These can occur when a single module
|
||||
# imports a module and also declares it in LOCAL_SHARED_LIBRARIES.
|
||||
NDK_BUILD_MODULES := $(call uniqify,$(NDK_BUILD_MODULES))
|
||||
|
||||
# Here are all of the files to build.
|
||||
NDK_BUILD_ALL_FILES := $(foreach file,$(NDK_BUILD_MODULES), \
|
||||
$(top_builddir)/cross/ndk-build/$(file))
|
||||
|
||||
# The C++ standard library must be extracted from the Android NDK
|
||||
# directories and included in the application package, if any module
|
||||
# requires the C++ standard library.
|
||||
|
||||
ifneq ($(NDK_BUILD_ANY_CXX_MODULE),)
|
||||
NDK_BUILD_SHARED += $(NDK_BUILD_CXX_SHARED)
|
||||
endif
|
||||
|
||||
define subr-1
|
||||
ifeq ($(suffix $(1)),.so)
|
||||
NDK_BUILD_SHARED += $(top_builddir)/cross/ndk-build/$(1)
|
||||
else
|
||||
ifeq ($(suffix $(1)),.a)
|
||||
NDK_BUILD_STATIC += $(top_builddir)/cross/ndk-build/$(1)
|
||||
endif
|
||||
endif
|
||||
endef
|
||||
|
||||
# Generate rules for each module.
|
||||
|
||||
$(foreach module,$(NDK_BUILD_MODULES),$(eval $(call subr-1,$(module))))
|
||||
|
||||
# Generate rules to build everything now.
|
||||
# Make sure to use the top_builddir currently defined.
|
||||
|
||||
NDK_TOP_BUILDDIR := $(top_builddir)
|
||||
$(NDK_BUILD_ALL_FILES) &:
|
||||
$(MAKE) -C $(NDK_TOP_BUILDDIR)/cross/ndk-build $(NDK_BUILD_MODULES)
|
57
cross/ndk-build/ndk-clear-vars.mk
Normal file
57
cross/ndk-build/ndk-clear-vars.mk
Normal file
|
@ -0,0 +1,57 @@
|
|||
# Copyright 2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU Emacs.
|
||||
|
||||
# GNU Emacs is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# GNU Emacs is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# ndk-build works by including a bunch of Makefiles which set
|
||||
# variables, and then having those Makefiles include another makefile
|
||||
# which actually builds targets.
|
||||
|
||||
LOCAL_MODULE :=
|
||||
LOCAL_MODULE_FILENAME :=
|
||||
LOCAL_SRC_FILES :=
|
||||
LOCAL_CPP_EXTENSION :=
|
||||
LOCAL_CPP_FEATURES :=
|
||||
LOCAL_C_INCLUDES :=
|
||||
LOCAL_CFLAGS :=
|
||||
LOCAL_CPPFLAGS :=
|
||||
LOCAL_STATIC_LIBRARIES :=
|
||||
LOCAL_SHARED_LIBRARIES :=
|
||||
LOCAL_WHOLE_STATIC_LIBRARIES :=
|
||||
LOCAL_LDLIBS :=
|
||||
LOCAL_LDFLAGS :=
|
||||
LOCAL_ALLOW_UNDEFINED_SYMBOLS :=
|
||||
LOCAL_ARM_MODE :=
|
||||
LOCAL_ARM_NEON :=
|
||||
LOCAL_DISABLE_FORMAT_STRING_CHECKS :=
|
||||
LOCAL_EXPORT_CFLAGS :=
|
||||
LOCAL_EXPORT_CPPFLAGS :=
|
||||
LOCAL_EXPORT_C_INCLUDES :=
|
||||
LOCAL_EXPORT_C_INCLUDE_DIRS :=
|
||||
LOCAL_EXPORT_LDFLAGS :=
|
||||
LOCAL_EXPORT_LDLIBS :=
|
||||
|
||||
# AOSP extensions.
|
||||
LOCAL_SRC_FILES_$(NDK_BUILD_ARCH) :=
|
||||
LOCAL_ASFLAGS_$(NDK_BUILD_ARCH) :=
|
||||
LOCAL_CFLAGS_$(NDK_BUILD_ARCH) :=
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES :=
|
||||
LOCAL_CLANG_ASFLAGS_$(NDK_BUILD_ARCH) :=
|
||||
LOCAL_IS_HOST_MODULE :=
|
||||
|
||||
# Emacs extensions!
|
||||
LOCAL_ASM_RULE_DEFINED :=
|
||||
LOCAL_ASM_RULE :=
|
||||
LOCAL_C_ADDITIONAL_FLAGS :=
|
24
cross/ndk-build/ndk-prebuilt-shared-library.mk
Normal file
24
cross/ndk-build/ndk-prebuilt-shared-library.mk
Normal file
|
@ -0,0 +1,24 @@
|
|||
### @configure_input@
|
||||
|
||||
# Copyright 2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU Emacs.
|
||||
|
||||
# GNU Emacs is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# GNU Emacs is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# ndk-build works by including a bunch of Makefiles which set
|
||||
# variables, and then having those Makefiles include another makefile
|
||||
# which actually builds targets.
|
||||
|
||||
$(warn Prebuilt shared libraries are not supported)
|
24
cross/ndk-build/ndk-prebuilt-static-library.mk
Normal file
24
cross/ndk-build/ndk-prebuilt-static-library.mk
Normal file
|
@ -0,0 +1,24 @@
|
|||
### @configure_input@
|
||||
|
||||
# Copyright 2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU Emacs.
|
||||
|
||||
# GNU Emacs is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# GNU Emacs is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# ndk-build works by including a bunch of Makefiles which set
|
||||
# variables, and then having those Makefiles include another makefile
|
||||
# which actually builds targets.
|
||||
|
||||
$(warn Prebuilt static libraries are not supported)
|
162
cross/ndk-build/ndk-resolve.mk
Normal file
162
cross/ndk-build/ndk-resolve.mk
Normal file
|
@ -0,0 +1,162 @@
|
|||
# Copyright 2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU Emacs.
|
||||
|
||||
# GNU Emacs is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# GNU Emacs is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# ndk-build works by including a bunch of Makefiles which set
|
||||
# variables, and then having those Makefiles include another makefile
|
||||
# which actually builds targets.
|
||||
|
||||
# List of system libraries to ignore.
|
||||
NDK_SYSTEM_LIBRARIES = z libz libc c libdl dl stdc++ libstdc++ log liblog android libandroid
|
||||
|
||||
# Save information.
|
||||
NDK_LOCAL_PATH_$(LOCAL_MODULE) := $(LOCAL_PATH)
|
||||
NDK_LOCAL_STATIC_LIBRARIES_$(LOCAL_MODULE) := $(LOCAL_STATIC_LIBRARIES) $(LOCAL_WHOLE_STATIC_LIBRARIES)
|
||||
NDK_LOCAL_WHOLE_LIBRARIES_$(LOCAL_MODULE) := $(LOCAL_WHOLE_STATIC_LIBRARIES)
|
||||
NDK_LOCAL_SHARED_LIBRARIES_$(LOCAL_MODULE) := $(LOCAL_SHARED_LIBRARIES)
|
||||
NDK_LOCAL_EXPORT_CFLAGS_$(LOCAL_MODULE) := $(LOCAL_EXPORT_CFLAGS)
|
||||
NDK_LOCAL_EXPORT_C_INCLUDES_$(LOCAL_MODULE) := $(LOCAL_EXPORT_C_INCLUDES) $(LOCAL_EXPORT_C_INCLUDE_DIRS)
|
||||
NDK_LOCAL_A_NAMES_$(LOCAL_MODULE) :=
|
||||
NDK_WHOLE_A_NAMES_$(LOCAL_MODULE) :=
|
||||
NDK_LOCAL_SO_NAMES_$(LOCAL_MODULE) :=
|
||||
NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE) :=
|
||||
|
||||
# List of all dependencies resolved for this module thus far.
|
||||
# Used to avoid infinite recursion.
|
||||
# Separate the variable which lists modules for which CFLAGS
|
||||
# have been resolved from the variable which lists modules
|
||||
# for which library dependencies have been resolved, in order
|
||||
# to catch the case where a library dependency is skipped
|
||||
# despite its CFLAGS being added.
|
||||
NDK_RESOLVED_$(LOCAL_MODULE) :=
|
||||
NDK_RESOLVED_CFLAGS_$(LOCAL_MODULE) :=
|
||||
|
||||
define ndk-resolve
|
||||
|
||||
ifeq ($$(filter $(1)$(and $(3),whole),$$(NDK_RESOLVED_CFLAGS_$(LOCAL_MODULE))),)
|
||||
# Always mark this module's cflags as having been resolved, even if
|
||||
# this is a whole library.
|
||||
NDK_RESOLVED_CFLAGS_$(LOCAL_MODULE) += $(1)
|
||||
|
||||
NDK_CFLAGS_$(LOCAL_MODULE) += $(NDK_LOCAL_EXPORT_CFLAGS_$(1))
|
||||
NDK_CFLAGS_$(LOCAL_MODULE) += $(addprefix -I,$(NDK_LOCAL_EXPORT_C_INCLUDES_$(1)))
|
||||
endif
|
||||
|
||||
ifeq ($$(filter $(1)$(and $(3),whole),$$(NDK_RESOLVED_$(LOCAL_MODULE))),)
|
||||
# Now append local libraries, as long as this library isn't a shared
|
||||
# library itself.
|
||||
ifeq ($(4),)
|
||||
|
||||
# Mark this module's library dependencies as having been resolved.
|
||||
NDK_RESOLVED_$(LOCAL_MODULE) += $(1)
|
||||
|
||||
# If this is a whole library, then mark this as resolved too, and
|
||||
# remove the library from the normal static library list.
|
||||
ifneq ($(3),)
|
||||
NDK_RESOLVED_$(LOCAL_MODULE) += $(1)whole
|
||||
endif
|
||||
|
||||
# If the module happens to be zlib, then add -lz to the shared library
|
||||
# flags.
|
||||
ifeq ($(strip $(1)),libz)
|
||||
NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE) += -lz
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(1)),z)
|
||||
NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE) += -lz
|
||||
endif
|
||||
|
||||
# Likewise for libdl.
|
||||
ifeq ($(strip $(1)),libdl)
|
||||
NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE) += -ldl
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(1)),dl)
|
||||
NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE) += -ldl
|
||||
endif
|
||||
|
||||
# Likewise for libstdc++.
|
||||
ifeq ($(strip $(1)),libstdc++)
|
||||
NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE) += -lstdc++
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(1)),dl)
|
||||
NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE) += -lstdc++
|
||||
endif
|
||||
|
||||
# Likewise for liblog.
|
||||
ifeq ($(strip $(1)),liblog)
|
||||
NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE) += -llog
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(1)),log)
|
||||
NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE) += -llog
|
||||
endif
|
||||
|
||||
# Likewise for libandroid.
|
||||
ifeq ($(strip $(1)),libandroid)
|
||||
NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE) += -landroid
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(1)),android)
|
||||
NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE) += -landroid
|
||||
endif
|
||||
|
||||
ifeq ($(findstring $(1),$(NDK_SYSTEM_LIBRARIES))$(2)$(3),)
|
||||
ifneq ($(findstring lib,$(1)),)
|
||||
NDK_LOCAL_SO_NAMES_$(LOCAL_MODULE) += $(1)_emacs.so
|
||||
else
|
||||
NDK_LOCAL_SO_NAMES_$(LOCAL_MODULE) += lib$(1)_emacs.so
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(2),)
|
||||
ifneq ($(findstring lib,$(1)),)
|
||||
NDK_LOCAL_A_NAMES_$(LOCAL_MODULE) += $(1).a
|
||||
else
|
||||
NDK_LOCAL_A_NAMES_$(LOCAL_MODULE) += lib$(1).a
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(3),)
|
||||
ifneq ($(findstring lib,$(1)),)
|
||||
NDK_WHOLE_A_NAMES_$(LOCAL_MODULE) += $(1).a
|
||||
else
|
||||
NDK_WHOLE_A_NAMES_$(LOCAL_MODULE) += lib$(1).a
|
||||
endif
|
||||
|
||||
# Remove this archive from the regular archive list, should it already
|
||||
# exists. Any given archive should only appear once, and if an
|
||||
# archive has been specified as whole it should always be whole.
|
||||
NDK_LOCAL_A_NAMES_$(LOCAL_MODULE) := $$(filter-out lib$(1).a,$$(NDK_LOCAL_A_NAMES_$(LOCAL_MODULE)))
|
||||
NDK_LOCAL_A_NAMES_$(LOCAL_MODULE) := $$(filter-out $(1).a,$$(NDK_LOCAL_A_NAMES_$(LOCAL_MODULE)))
|
||||
endif
|
||||
endif
|
||||
|
||||
$$(foreach module,$$(NDK_LOCAL_STATIC_LIBRARIES_$(1)),$$(eval $$(call ndk-resolve,$$(module),1,,$(or $(4),$(if $(2)$(3),,1)))))
|
||||
$$(foreach module,$$(NDK_LOCAL_SHARED_LIBRARIES_$(1)),$$(eval $$(call ndk-resolve,$$(module),,,$(or $(4),$(if $(2)$(3),,1)))))
|
||||
$$(foreach module,$$(NDK_LOCAL_WHOLE_LIBRARIES_$(1)),$$(eval $$(call ndk-resolve,$$(module),,1,$(or $(4),$(if $(2)$(3),,1)))))
|
||||
endif
|
||||
|
||||
endef
|
||||
|
||||
# Add shared libraries to the shared object names when they appear as
|
||||
# a top level dependency. However, do not recursively add the names
|
||||
# of this module's shared library dependencies, if it is just a shared
|
||||
# library, since it will link to those shared libraries itself.
|
||||
$(foreach module,$(LOCAL_SHARED_LIBRARIES),$(eval $(call ndk-resolve,$(module),,,)))
|
||||
$(foreach module,$(LOCAL_STATIC_LIBRARIES),$(eval $(call ndk-resolve,$(module),1,,)))
|
||||
$(foreach module,$(LOCAL_WHOLE_STATIC_LIBRARIES), $(eval $(call ndk-resolve,$(module),,1,)))
|
55
cross/verbose.mk.android
Normal file
55
cross/verbose.mk.android
Normal file
|
@ -0,0 +1,55 @@
|
|||
### verbose.mk --- Makefile fragment for GNU Emacs during
|
||||
### cross-compilation.
|
||||
|
||||
## Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
## This file is part of GNU Emacs.
|
||||
|
||||
## GNU Emacs is free software: you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published by
|
||||
## the Free Software Foundation, either version 3 of the License, or
|
||||
## (at your option) any later version.
|
||||
##
|
||||
## GNU Emacs is distributed in the hope that it will be useful,
|
||||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License
|
||||
## along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# 'make' verbosity.
|
||||
V = 0
|
||||
ifeq (${V},1)
|
||||
AM_V_AR =
|
||||
AM_V_at =
|
||||
AM_V_CC =
|
||||
AM_V_CXX =
|
||||
AM_V_CCLD =
|
||||
AM_V_CXXLD =
|
||||
AM_V_GEN =
|
||||
else
|
||||
|
||||
# Whether $(info ...) works. This is to work around a bug in GNU Make
|
||||
# 4.3 and earlier, which implements $(info MSG) via two system calls
|
||||
# { write (..., "MSG", 3); write (..., "\n", 1); }
|
||||
# which looks bad when make -j interleaves two of these at about the same time.
|
||||
#
|
||||
# Later versions of GNU Make have the 'notintermediate' feature,
|
||||
# so assume that $(info ...) works if this feature is present.
|
||||
#
|
||||
have_working_info = $(filter notintermediate,$(value .FEATURES))
|
||||
#
|
||||
# The workaround is to use the shell and 'echo' rather than $(info ...).
|
||||
# The workaround is done only for AM_V_ELC and AM_V_ELN,
|
||||
# since the bug is not annoying elsewhere.
|
||||
|
||||
AM_V_AR = @$(info $ AR $@)
|
||||
AM_V_at = @
|
||||
AM_V_CC = @$(info $ CC $@)
|
||||
AM_V_CXX = @$(info $ CXX $@)
|
||||
AM_V_CCLD = @$(info $ CCLD $@)
|
||||
AM_V_CXXLD = @$(info $ CXXLD $@)
|
||||
AM_V_GEN = @$(info $ GEN $@)
|
||||
AM_V_NO_PD = --no-print-directory
|
||||
endif
|
|
@ -146,6 +146,8 @@ EMACSSOURCES= \
|
|||
${srcdir}/glossary.texi \
|
||||
${srcdir}/ack.texi \
|
||||
${srcdir}/kmacro.texi \
|
||||
${srcdir}/android.texi \
|
||||
${srcdir}/input.texi \
|
||||
$(EMACS_XTRA)
|
||||
|
||||
## Disable implicit rules.
|
||||
|
|
791
doc/emacs/android.texi
Normal file
791
doc/emacs/android.texi
Normal file
|
@ -0,0 +1,791 @@
|
|||
@c This is part of the Emacs manual.
|
||||
@c Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
@c See file emacs.texi for copying conditions.
|
||||
@node Android
|
||||
@appendix Emacs and Android
|
||||
@cindex Android
|
||||
|
||||
Android is a mobile operating system developed by the Open Handset
|
||||
Alliance. This section describes the peculiarities of using Emacs on
|
||||
an Android device running Android 2.2 or later.
|
||||
|
||||
Android devices commonly rely on user input through a touch screen
|
||||
or digitizer device and on-screen keyboard. For more information
|
||||
about using such devices with Emacs, @pxref{Other Input Devices}.
|
||||
|
||||
@menu
|
||||
* What is Android?:: Preamble.
|
||||
* Android Startup:: Starting up Emacs on Android.
|
||||
* Android File System:: The Android file system.
|
||||
* Android Document Providers:: Accessing files from other programs.
|
||||
* Android Environment:: Running Emacs under Android.
|
||||
* Android Windowing:: The Android window system.
|
||||
* Android Fonts:: Font selection under Android.
|
||||
* Android Troubleshooting:: Dealing with problems.
|
||||
* Android Software:: Getting extra software.
|
||||
@end menu
|
||||
|
||||
@node What is Android?
|
||||
@section Android History
|
||||
|
||||
Android is an operating system for mobile devices developed by the
|
||||
Open Handset Alliance, a group of companies interested in developing
|
||||
handsets that can run a common set of software. It is supposedly free
|
||||
software.
|
||||
|
||||
Like the X Consortium of times past, the Open Handset Alliance
|
||||
believes that ``openness'' (namely, the regular release of the Android
|
||||
source code) is simply a tool to increase the popularity of the
|
||||
Android platform. Computer companies normally produce proprietary
|
||||
software. The companies in the Open Handset Alliance are no different
|
||||
-- most versions of Android installed on devices are proprietary, by
|
||||
virtue of containing proprietary components, that often cannot even be
|
||||
replaced by the user.
|
||||
|
||||
Android is not designed to respect users' freedom. Almost all
|
||||
versions of Android (including some which are supposedly free
|
||||
software) include support for Digital Restrictions Management,
|
||||
technology that is designed to limit users' ability to copy media to
|
||||
and from their own devices. Most Android devices also come with
|
||||
proprietary Google applications which are required to run the system,
|
||||
and many other Android applications.
|
||||
|
||||
Thus, it must be necessary to consider Android proprietary software
|
||||
from a practical standpoint. That is an injustice. If you use
|
||||
Android, we urge you to switch to a free operating system, if only for
|
||||
your freedom's sake.
|
||||
|
||||
We support GNU Emacs on proprietary operating systems because we
|
||||
hope this taste of freedom will inspire users to escape from them.
|
||||
|
||||
@node Android Startup
|
||||
@section Starting Emacs on Android
|
||||
|
||||
Emacs is not installed on Android devices from source code or
|
||||
through a package manager. Instead, Emacs is compiled for Android on
|
||||
a different operating system, with the resulting binaries packaged
|
||||
into an archive, that is then transferred to the system and installed.
|
||||
|
||||
After being installed, the system places an application icon on the
|
||||
desktop (a.k.a@: ``home screen''.) Emacs then starts up once the
|
||||
application icon is clicked.
|
||||
|
||||
@cindex ``adb logcat''
|
||||
|
||||
During startup, Emacs will display messages in the system log
|
||||
buffer; reading that buffer during start-up requires the Android Debug
|
||||
Bridge (@command{adb}) utility to be installed on another computer.
|
||||
|
||||
After enabling the ``USB Debugging'' feature on the Android system,
|
||||
and connecting it via USB to another system with the @command{adb}
|
||||
utility installed, the log can be viewed by running the following
|
||||
command on that other system:
|
||||
|
||||
@example
|
||||
$ adb logcat | grep -E "(android_run_debug_thread|[Ee]macs)"
|
||||
@end example
|
||||
|
||||
Assuming that the @command{adb} utility is installed on a GNU/Linux
|
||||
or Unix system, follow the steps below to connect to your device.
|
||||
|
||||
@enumerate
|
||||
@item
|
||||
Enable ``developer options'' on your device, by going to the ``About''
|
||||
page in the system settings application and clicking on the ``build
|
||||
version'' or ``kernel version'' items five to seven times.
|
||||
|
||||
@item
|
||||
Open the ``developer options'' settings page, which should be under
|
||||
the ``system'' page in the settings application.
|
||||
|
||||
@item
|
||||
Turn on the switch ``USB debugging''.
|
||||
|
||||
@item
|
||||
Connect one end of a USB cable to your device, and the other end to
|
||||
your computer's USB port.
|
||||
|
||||
@item
|
||||
Run the command @command{adb shell} on your computer. This will fail
|
||||
or hang because you have not yet granted your computer permission to
|
||||
access the connected device.
|
||||
|
||||
@item
|
||||
Confirm the pop-up displayed on your device asking whether or not it
|
||||
should allow access from your computer.
|
||||
@end enumerate
|
||||
|
||||
Depending on the versions of Android and @command{adb} installed,
|
||||
there may be other ways to establish a connection. See the official
|
||||
documentation at
|
||||
@url{https://developer.android.com/studio/command-line/adb} for more
|
||||
details.
|
||||
|
||||
Once Emacs starts up, simply running the command @command{logcat} as
|
||||
an asynchronous shell command (@pxref{Shell}) will display the log
|
||||
buffer.
|
||||
|
||||
@cindex emacsclient wrapper, android
|
||||
Since there is no other way to start the @command{emacsclient}
|
||||
program (@pxref{Emacs Server}) from another Android program, Emacs
|
||||
provides a wrapper around the @command{emacsclient} program, which is
|
||||
registered with the system as an application that can open all text
|
||||
files.
|
||||
|
||||
When that wrapper is selected as the program with which to open a
|
||||
file, it invokes @command{emacsclient} with the options
|
||||
@command{--reuse-frame}, @command{--timeout=10}, @command{--no-wait},
|
||||
and the name of the file being opened. Then, upon success, the focus
|
||||
is transferred to any open Emacs frame.
|
||||
|
||||
However, if Emacs is not running at the time the wrapper is opened,
|
||||
it starts Emacs and gives it the file to open as an argument. Note
|
||||
that if that Emacs in turn does not start the Emacs server, subsequent
|
||||
attempts to open the file with the wrapper will fail.
|
||||
|
||||
@cindex /content/by-authority directory, android
|
||||
Some files are given to Emacs as ``content identifiers'' that the
|
||||
system provides access to outside the normal filesystem APIs. Emacs
|
||||
uses a pseudo-directory named @file{/content/by-authority} to access
|
||||
those files. Do not make any assumptions about the contents of this
|
||||
directory, or try to open files in it yourself.
|
||||
|
||||
This feature is not provided on Android 4.3 and earlier, in which
|
||||
case such files are copied to a temporary directory before being
|
||||
opened.
|
||||
|
||||
@node Android File System
|
||||
@section What Files Emacs Can Access on Android
|
||||
@cindex /assets directory, android
|
||||
|
||||
Emacs exposes a special directory on Android systems: the name of
|
||||
the directory is @file{/assets}, and it contains the @file{etc},
|
||||
@file{lisp} and @file{info} directories which are normally installed
|
||||
in @file{/usr/share/emacs} directory on GNU and Unix systems. On
|
||||
Android systems, the Lisp emulation of @command{ls} (@pxref{ls in
|
||||
Lisp}) is also enabled by default, as the @command{ls} binary which
|
||||
comes with the system varies by manufacturer and usually does not
|
||||
support all of the features required by Emacs. One copy of
|
||||
@command{ls} distributed with some Android systems is even known to
|
||||
lack support for the @code{-l} flag.
|
||||
|
||||
@cindex limitations of the /assets directory
|
||||
|
||||
This directory exists because Android does not extract the contents
|
||||
of application packages on to the file system while unpacking them,
|
||||
but instead requires programs like Emacs to access its contents using
|
||||
a special ``asset manager'' interface. Here are the peculiarities
|
||||
that result from such an implementation:
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
Subprocesses (such as @command{ls}) can not run from the
|
||||
@file{/assets} directory; if you try to run a subprocess with
|
||||
@code{current-directory} set to @file{/assets},
|
||||
@file{/content/storage} or a subdirectory thereof, it will run from
|
||||
the home directory instead.
|
||||
|
||||
@item
|
||||
There are no @file{.} and @file{..} directories inside the
|
||||
@file{/assets} or @file{/content} directory.
|
||||
|
||||
@item
|
||||
Files in the @file{/assets} directory are always read only, and may be
|
||||
read in to memory more than once each time they are opened.
|
||||
@end itemize
|
||||
|
||||
Aside from the @file{/assets} directory, Android programs normally
|
||||
have access to four other directories. They are:
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
The @dfn{app data} directory. This also serves as the home directory
|
||||
for Emacs, and is always accessible read-write.
|
||||
|
||||
@item
|
||||
The @dfn{app library} directory. This is automatically appended to
|
||||
@code{exec-path} and made @code{exec-directory} upon startup, and
|
||||
contains utility executables alongside Emacs itself.
|
||||
|
||||
@item
|
||||
The @dfn{external storage} directory. This is accessible to Emacs
|
||||
when the user grants the ``Files and Media'' permission to Emacs via
|
||||
system settings.
|
||||
|
||||
@item
|
||||
Directories provided by @dfn{document providers} on Android 5.0 and
|
||||
later. These directories exist outside the normal Unix filesystem,
|
||||
containing files provided by external programs (@pxref{Android
|
||||
Document Providers}.)
|
||||
@end itemize
|
||||
|
||||
Despite ordinary installations of Android not having files within
|
||||
the (normally read-only) root directory named @file{content} or
|
||||
@file{assets}, you may want to access real files by these names if the
|
||||
Android installation in use has been customized. These files will
|
||||
conflict with the aformentioned special directories, but can
|
||||
nevertheless be accessed by writing their names relative to the
|
||||
``parent'' directory of the root directory, as so illustrated:
|
||||
@file{/../content}, @file{/../assets}.
|
||||
|
||||
The external storage directory is found at @file{/sdcard}. The
|
||||
other directories are not found at any fixed location (but see below),
|
||||
although the app data directory is typically symlinked to
|
||||
@file{/data/data/org.gnu.emacs/files}.
|
||||
|
||||
@cindex app library directory, android
|
||||
@cindex where is emacsclient under android
|
||||
Older versions of Android used to place the app library directory
|
||||
under the name @file{lib} in the parent of the app data directory.
|
||||
Today, this directory is often placed in a directory with a randomly
|
||||
generated name under @file{/data/app}.
|
||||
|
||||
For the convenience of scripts running within applications sharing
|
||||
the same user ID as Emacs (which have no access to the
|
||||
@code{exec-directory} variable), a fairly considerable effort is made
|
||||
at startup to symlink the application library directory to its
|
||||
traditional location within the parent of the app data directory.
|
||||
|
||||
If Emacs is reinstalled and the location of the app library
|
||||
directory consequentially changes, that symlink will also be updated
|
||||
to point to its new location the next time Emacs is started by the
|
||||
system.
|
||||
|
||||
@cindex temp~unlinked.NNNN files, Android
|
||||
On Android devices running very old (2.6.29) versions of the Linux
|
||||
kernel, Emacs needs to create files named starting with
|
||||
@file{temp~unlinked} in the the temporary file directory in order to
|
||||
read from asset files. Do not create files with such names yourself,
|
||||
or they may be overwritten or removed.
|
||||
|
||||
@cindex file system limitations, Android 11
|
||||
On Android 11 and later, the Android system restricts applications
|
||||
from accessing files in the @file{/sdcard} directory using
|
||||
file-related system calls such as @code{open} and @code{readdir}.
|
||||
|
||||
This restriction is known as ``Scoped Storage'', and supposedly
|
||||
makes the system more secure. Unfortunately, it also means that Emacs
|
||||
cannot access files in those directories, despite holding the
|
||||
necessary permissions. Thankfully, the Open Handset Alliance's
|
||||
version of Android allows this restriction to be disabled on a
|
||||
per-program basis; the corresponding option in the system settings
|
||||
panel is:
|
||||
|
||||
@example
|
||||
System -> Apps -> Special App Access -> All files access -> Emacs
|
||||
@end example
|
||||
|
||||
After you disable or enable this setting as appropriate and grant
|
||||
Emacs the ``Files and Media'' permission, it will be able to access
|
||||
files under @file{/sdcard} as usual. These settings are not present
|
||||
on some proprietary versions of Android.
|
||||
|
||||
@node Android Document Providers
|
||||
@section Accessing Files from Other Programs on Android
|
||||
@cindex document providers, Android
|
||||
@cindex /content/storage directory, Android
|
||||
|
||||
Android 5.0 introduces a new sort of program, the ``document
|
||||
provider'': these programs are small programs that provide access to
|
||||
their own files outside both the asset manager and the Unix
|
||||
filesystem. Emacs supports accessing files and directories they
|
||||
provide, placing their files within the directory
|
||||
@file{/content/storage}.
|
||||
|
||||
@findex android-request-directory-access
|
||||
Before Emacs is granted access to any of these directories, it must
|
||||
first request the right to access it. This is done by running the
|
||||
command (@pxref{M-x}) @code{android-request-directory-access}, which
|
||||
displays a file selection dialog.
|
||||
|
||||
If a directory is selected within this dialog, its contents are
|
||||
subsequently made available within a new directory named
|
||||
@file{/content/storage/@var{authority}/@var{id}}, where
|
||||
@var{authority} is the name of the document provider, and @var{id} is
|
||||
a unique identifier assigned to the directory by the document
|
||||
provider.
|
||||
|
||||
The same limitations applied to the @file{/assets} directory
|
||||
(@pxref{Android File System}) are applied when creating sub-processes
|
||||
within those directories, because they do not exist within the Unix
|
||||
file-system. In addition, although Emacs can normally write and
|
||||
create files inside these directories, it cannot create symlinks or
|
||||
hard links.
|
||||
|
||||
Since document providers are allowed to perform expensive network
|
||||
operations to obtain file contents, a file access operation within one
|
||||
of these directories has the potential to take a significant amount of
|
||||
time.
|
||||
|
||||
@node Android Environment
|
||||
@section Running Emacs under Android
|
||||
|
||||
From the perspective of users, Android is mostly a single user
|
||||
operating system; however, from the perspective of applications and
|
||||
Emacs, the system has an overwhelming number of users.
|
||||
|
||||
Each application runs in its own user, with its home directory set
|
||||
to its app data directory (@pxref{Android File
|
||||
System}.)@footnote{Except in cases where a ``shared user ID'' is
|
||||
specified and other applications signed using the same ``package
|
||||
signing key'' are installed, in which case Emacs runs as the same user
|
||||
and has access to the same files as each of the aformentioned
|
||||
applications.}
|
||||
|
||||
Each application is also prohibited from accessing many system
|
||||
directories and the app data directories of other applications.
|
||||
|
||||
Emacs comes with several binaries. While being executable files,
|
||||
they are packaged as libraries in the library directory, because
|
||||
otherwise the system will not unpack them while Emacs is being
|
||||
installed. This means, instead of specifying @code{ctags} or
|
||||
@code{emacsclient} in a subprocess, Lisp code must specify
|
||||
@code{libctags.so} or @code{libemacsclient.so} on the command line
|
||||
instead when starting either of those programs in a subprocess; to
|
||||
determine which names to use, consult the values of the variables
|
||||
@code{ctags-program-name}, @code{etags-program-name},
|
||||
@code{hexl-program-name}, @code{emacsclient-program-name},
|
||||
@code{movemail-program-name}, and @code{ebrowse-program-name}.
|
||||
@xref{Subprocess Creation,,, elisp, the Emacs Lisp Reference Manual}.
|
||||
|
||||
The @file{/assets} directory containing Emacs start-up files is
|
||||
supposed to be inaccessible to processes not directly created by
|
||||
@code{zygote}, the system service responsible for starting
|
||||
applications. Since required Lisp is found in the @file{/assets}
|
||||
directory, it would thus follow that it is not possible for Emacs to
|
||||
start itself as a subprocess. A special binary named
|
||||
@command{libandroid-emacs.so} is provided with Emacs, and does its
|
||||
best to start Emacs for the purpose of running Lisp in batch mode.
|
||||
However, the approach it takes was devised by reading Android source
|
||||
code, and is not sanctioned by the Android compatibility definition
|
||||
documents, so your mileage may vary.
|
||||
|
||||
@cindex call-process, Android
|
||||
@vindex android-use-exec-loader
|
||||
Android 10 and later also prohibit Emacs itself from running
|
||||
executables inside the app data directory, obstensibly for security
|
||||
reasons. On these systems, Emacs normally applies a workaround;
|
||||
however, this workaround requires running all sub-processes through
|
||||
another subprocess which implements an executable loader and applies
|
||||
process tracing to all its children, which may prove to be problematic
|
||||
for various different reasons. In that case, the workaround can be
|
||||
disabled by changing the variable @code{android-use-exec-loader} to
|
||||
@code{nil}.
|
||||
|
||||
When this workaround is in effect, process IDs retrieved through the
|
||||
@code{process-id} function will be that of the executable loader
|
||||
process; its child will belong to the same process group as the
|
||||
loader. As a result, @code{interrupt-process}, and other related
|
||||
functions will work correctly, but using the process ID returned by
|
||||
@code{process-id} for other purposes will not.
|
||||
|
||||
One side effect of the mechanism by which process tracing is carried
|
||||
out is that job control facilities inside inferior shells
|
||||
(@pxref{Interactive Shell}) will not be able to stop processes, and
|
||||
sending the @code{SIGSTOP} signal to a subprocess created by Emacs
|
||||
will appear to have no effect.
|
||||
|
||||
In addition, Android 12 also terminates subprocesses which are
|
||||
consuming CPU while Emacs itself is in the background. The system
|
||||
determines which processes are consuming too much CPU in intervals of
|
||||
five minutes, and terminates the process that has consumed the most
|
||||
CPU time.
|
||||
|
||||
Android 12.1 and Android 13 provide an option to disable this
|
||||
behavior; to use it, enable ``USB debugging'' (@pxref{Android
|
||||
Startup}) connect the Android system to another computer, and run:
|
||||
|
||||
@example
|
||||
$ adb shell "settings put global settings_enable_monitor_phantom_procs false"
|
||||
@end example
|
||||
|
||||
@section Running Emacs in the Background
|
||||
@cindex emacs killed, android
|
||||
@cindex emacs in the background, android
|
||||
|
||||
Application processes are treated as disposable entities by the
|
||||
system. When all Emacs frames move to the background, Emacs might be
|
||||
terminated by the system at any time, for the purpose of saving system
|
||||
resources.
|
||||
|
||||
On Android 7.1 and earlier, Emacs tells the system to treat it as a
|
||||
``background service''. The system will try to avoid killing Emacs
|
||||
unless the system is stressed for memory.
|
||||
|
||||
Android 8.0 removed the ability for background services to receive
|
||||
such special treatment. However, Emacs applies a workaround: the
|
||||
system considers applications that create a permanent notification to
|
||||
be performing active work, and will avoid killing such applications.
|
||||
Thus, on those systems, Emacs displays a permanent notification for as
|
||||
long as it is running. Once the notification is displayed, it can be
|
||||
safely hidden through the system settings without resulting in Emacs
|
||||
being killed.
|
||||
|
||||
However, it is not guaranteed that the system will not kill Emacs
|
||||
even if a notification is being displayed. While the Open Handset
|
||||
Alliance's sample implementation of Android behaves correctly, many
|
||||
manufacturers place additional restrictions on program execution in
|
||||
the background in their proprietary versions of Android. There is a
|
||||
list of such troublesome manufacturers and sometimes workarounds at
|
||||
@url{https://dontkillmyapp.com/}.
|
||||
|
||||
@section Android Permissions
|
||||
@cindex external storage, android
|
||||
|
||||
Android also defines a permissions system that determines what
|
||||
system services Emacs is allowed to access. Programs must specify
|
||||
what permissions they want; what then happens depends on the version
|
||||
of Android being used:
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
On Android 5.1 and earlier, Emacs automatically receives the following
|
||||
permissions it has requested upon being installed:
|
||||
|
||||
@itemize @minus
|
||||
@item
|
||||
@code{android.permission.READ_CONTACTS}
|
||||
@item
|
||||
@code{android.permission.WRITE_CONTACTS}
|
||||
@item
|
||||
@code{android.permission.VIBRATE}
|
||||
@item
|
||||
@code{android.permission.ACCESS_COARSE_LOCATION}
|
||||
@item
|
||||
@code{android.permission.ACCESS_NETWORK_STATE}
|
||||
@item
|
||||
@code{android.permission.INTERNET}
|
||||
@item
|
||||
@code{android.permission.SET_WALLPAPER}
|
||||
@item
|
||||
@code{android.permission.READ_EXTERNAL_STORAGE}
|
||||
@item
|
||||
@code{android.permission.WRITE_EXTERNAL_STORAGE}
|
||||
@item
|
||||
@code{android.permission.SEND_SMS}
|
||||
@item
|
||||
@code{android.permission.RECEIVE_SMS}
|
||||
@item
|
||||
@code{android.permission.RECEIVE_MMS}
|
||||
@item
|
||||
@code{android.permission.WRITE_SMS}
|
||||
@item
|
||||
@code{android.permission.READ_SMS}
|
||||
@item
|
||||
@code{android.permission.NFC}
|
||||
@item
|
||||
@code{android.permission.TRANSMIT_IR}
|
||||
@item
|
||||
@code{android.permission.READ_PHONE_STATE}
|
||||
@item
|
||||
@code{android.permission.WAKE_LOCK}
|
||||
@item
|
||||
@code{android.permission.FOREGROUND_SEVICE}
|
||||
@item
|
||||
@code{android.permission.REQUEST_INSTALL_PACKAGES}
|
||||
@item
|
||||
@code{android.permission.REQUEST_DELETE_PACKAGES}
|
||||
@item
|
||||
@code{android.permission.SYSTEM_ALERT_WINDOW}
|
||||
@item
|
||||
@code{android.permission.RECORD_AUDIO}
|
||||
@item
|
||||
@code{android.permission.CAMERA}
|
||||
@end itemize
|
||||
|
||||
While most of these permissions are left unused by Emacs itself, they
|
||||
are declared by Emacs as they could be useful for other programs; for
|
||||
example, the permission to access contacts may be useful for EUDC.
|
||||
|
||||
@item
|
||||
On Android 6.0 and later, Emacs only receives the following
|
||||
permissions upon installation:
|
||||
|
||||
@itemize @minus
|
||||
@item
|
||||
@code{android.permission.VIBRATE}
|
||||
@item
|
||||
@code{android.permission.ACCESS_NETWORK_STATE}
|
||||
@item
|
||||
@code{android.permission.INTERNET}
|
||||
@item
|
||||
@code{android.permission.SET_WALLPAPER}
|
||||
@item
|
||||
@code{android.permission.NFC}
|
||||
@item
|
||||
@code{android.permission.TRANSMIT_IR}
|
||||
@item
|
||||
@code{android.permission.WAKE_LOCK}
|
||||
@item
|
||||
@code{android.permission.POST_NOTIFICATIONS}
|
||||
@end itemize
|
||||
|
||||
Other permissions must be granted by the user through the system
|
||||
settings application. Consult the manufacturer of your device for
|
||||
more details, as how to do this varies by device.
|
||||
@end itemize
|
||||
|
||||
@node Android Windowing
|
||||
@section The Android Window System
|
||||
|
||||
Android has an unusual window system; there, all windows are
|
||||
maximized or full-screen, and only one window can be displayed at a
|
||||
time. On larger devices, the system allows up to four windows to be
|
||||
tiled on the screen at any time.
|
||||
|
||||
Windows on Android do not continue to exist indefinitely after they
|
||||
are created. Instead, the system may choose to close windows that are
|
||||
not on screen in order to save memory, with the assumption that the
|
||||
program will save its contents to disk and restore them later, when
|
||||
the user asks for it to be opened again. As this is obviously not
|
||||
possible with Emacs, Emacs separates the resources associated with a
|
||||
frame from its system window.
|
||||
|
||||
Each system window created (including the initial window created
|
||||
during Emacs startup) is appended to a list of windows that do not
|
||||
have associated frames. When a frame is created, Emacs looks up any
|
||||
window within that list, and displays the contents of the frame
|
||||
within; if there is no window at all, then one is created. Likewise,
|
||||
when a new window is created by the system, Emacs places the contents
|
||||
of any frame that is not already displayed within a window inside.
|
||||
When a frame is closed, the corresponding system window is also
|
||||
closed. Upon startup, the system creates a window itself (within
|
||||
which Emacs displays the first window system frame shortly
|
||||
thereafter.) Emacs differentiates between that window and windows
|
||||
created on behalf of other frames to determine what to do when the
|
||||
system window associated with a frame is closed:
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
When the system closes the window created during application startup
|
||||
in order to save memory, Emacs retains the frame for when that window
|
||||
is created later.
|
||||
|
||||
@item
|
||||
When the user closes the window created during application startup,
|
||||
and the window was not previously closed by the system in order to
|
||||
save resources, Emacs deletes any frame displayed within that window.
|
||||
|
||||
@item
|
||||
When the user or the system closes any window created by Emacs on
|
||||
behalf of a specific frame, Emacs deletes the frame displayed within
|
||||
that window.
|
||||
@end itemize
|
||||
|
||||
@cindex windowing limitations, android
|
||||
@cindex frame parameters, android
|
||||
Emacs only supports a limited subset of GUI features on Android; the
|
||||
limitations are as follows:
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
Scroll bars are not supported, as they are close to useless on Android
|
||||
devices.
|
||||
|
||||
@item
|
||||
The @code{alpha}, @code{alpha-background}, @code{z-group},
|
||||
@code{override-redirect}, @code{mouse-color}, @code{title},
|
||||
@code{wait-for-wm}, @code{sticky}, @code{undecorated} and
|
||||
@code{tool-bar-position} frame parameters (@pxref{Frame Parameters,,,
|
||||
elisp, the Emacs Lisp Reference Manual}) are unsupported.
|
||||
|
||||
@item
|
||||
On Android 4.0 and earlier, the @code{fullscreen} frame parameter is
|
||||
always @code{maximized} for top-level frames; on later versions of
|
||||
Android, it can also be @code{fullscreen}.
|
||||
@end itemize
|
||||
|
||||
@cindex selections, android
|
||||
@cindex android clipboard
|
||||
Emacs does not implement all selection related features supported
|
||||
under the X Window System on Android. For example, only the
|
||||
@code{CLIPBOARD} and @code{PRIMARY} selections (@pxref{Cut and Paste})
|
||||
are supported, and Emacs is only able to set selections to plain text.
|
||||
|
||||
In addition, the Android system itself places certain restrictions
|
||||
on what selection data Emacs can access:
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
On Android 2.3 and earlier, the function @code{gui-selection-owner-p}
|
||||
always returns @code{nil} for the clipboard selection.
|
||||
|
||||
@item
|
||||
Between Android 3.0 and Android 9.0, Emacs is able to access the
|
||||
clipboard whenever it wants, and @code{gui-selection-owner-p} always
|
||||
returns accurate results.
|
||||
|
||||
@item
|
||||
Under Android 10.0 and later, Emacs can only access clipboard data
|
||||
when one of its frames has the input focus, and
|
||||
@code{gui-selection-owner-p} always returns @code{nil} for the
|
||||
clipboard selection.
|
||||
@end itemize
|
||||
|
||||
Since the Android system itself has no concept of a primary
|
||||
selection, Emacs provides an emulation instead. This means there is
|
||||
no way to transfer the contents of the primary selection to another
|
||||
application via cut-and-paste.
|
||||
|
||||
@vindex android-pass-multimedia-buttons-to-system
|
||||
@cindex volume/multimedia buttons, Android
|
||||
The volume keys are normally reserved by Emacs and used to provide
|
||||
the ability to quit Emacs without a physical keyboard
|
||||
(@pxref{On-Screen Keyboards}.) However, if you want them to adjust
|
||||
the volume instead, you can set the variable
|
||||
@code{android-pass-multimedia-buttons-to-system} to a non-@code{nil}
|
||||
value; note that you will no longer be able to quit Emacs using the
|
||||
volume buttons in that case.
|
||||
|
||||
@cindex dialog boxes, android
|
||||
Emacs is unable to display dialog boxes (@pxref{Dialog Boxes}) while
|
||||
it does not have the input focus on Android 6.0 or later. If this is
|
||||
important to you, this ability can be restored by granting Emacs
|
||||
permission to display over other programs. Normally, this can be done
|
||||
from the:
|
||||
|
||||
@example
|
||||
System -> Apps -> Emacs -> More -> Display over other apps
|
||||
@end example
|
||||
|
||||
menu in the system settings, but this procedure may vary by device.
|
||||
|
||||
@cindex keyboard modifiers, android
|
||||
There is a direct relation between physical modifier keys and Emacs
|
||||
modifiers (@pxref{Modifier Keys}) reported within key events, subject
|
||||
to a single exception: if @key{Alt} on your keyboard is depressed,
|
||||
then the @key{Meta} modifier will be reported by Emacs in its place,
|
||||
and vice versa. This irregularity is since most keyboards posses no
|
||||
special @key{Meta} key, and the @key{Alt} modifier is seldom employed
|
||||
in Emacs.
|
||||
|
||||
Bear in mind that Android uses a different name for the @key{Super}
|
||||
modifier: it is referred to as @key{SYM} on Android keyboards and
|
||||
within the Settings keymap menu.
|
||||
|
||||
@node Android Fonts
|
||||
@section Font Backends and Selection under Android
|
||||
@cindex fonts, android
|
||||
|
||||
Emacs supports two font backends under Android: they are respectively
|
||||
named @code{sfnt-android} and @code{android}.
|
||||
|
||||
Upon startup, Emacs enumerates all the TrueType format fonts in the
|
||||
directories @file{/system/fonts} and @file{/product/fonts}, and the
|
||||
@file{fonts} directory (@dfn{user fonts directory}) inside the Emacs
|
||||
home directory. Emacs assumes there will always be a font named
|
||||
``Droid Sans Mono'', and then defaults to using this font. These
|
||||
fonts are then displayed by the @code{sfnt-android} font driver.
|
||||
|
||||
When running on Android, Emacs currently lacks support for OpenType
|
||||
fonts. This means that only a subset of the fonts installed on the
|
||||
system are currently available to Emacs. If you are interested in
|
||||
lifting this limitation, please contact @email{emacs-devel@@gnu.org}.
|
||||
|
||||
If the @code{sfnt-android} font driver fails to find any fonts at
|
||||
all, Emacs falls back to the @code{android} font driver. This is a
|
||||
very lousy font driver, because of limitations and inaccuracies in the
|
||||
font metrics provided by the Android platform. In that case, Emacs
|
||||
uses the ``Monospace'' typeface configured on your system; this should
|
||||
always be Droid Sans Mono.
|
||||
|
||||
@cindex TrueType GX fonts, android
|
||||
@cindex distortable fonts, android
|
||||
|
||||
Like on X systems, Emacs supports distortable fonts under Android.
|
||||
These fonts (also termed ``TrueType GX fonts'', ``variable fonts'',
|
||||
and ``multiple master fonts'') provide multiple different styles
|
||||
(``Bold'', ``Italic'', etc) using a single font file.
|
||||
|
||||
When a user-installed distortable font is found, each font that a
|
||||
previously discovered font provided will no longer be used. In
|
||||
addition, any previously specified distortable fonts with the same
|
||||
family name are also removed. When a conventional font is found, any
|
||||
previous conventional font with the same style and family will be
|
||||
removed; distortable fonts with the same family will no longer be used
|
||||
to provide that style.
|
||||
|
||||
@node Android Troubleshooting
|
||||
@section Troubleshooting Startup Problems on Android
|
||||
@cindex troubleshooting, android
|
||||
|
||||
@cindex emacs -Q, android
|
||||
@cindex emacs --debug-init, android
|
||||
Since Android has no command line, there is normally no way to
|
||||
specify command-line arguments when starting Emacs. This is very
|
||||
nasty when you make a mistake in your Emacs initialization files that
|
||||
prevents Emacs from starting up at all, as the system normally
|
||||
prevents other programs from accessing Emacs's home directory.
|
||||
@xref{Initial Options}.
|
||||
|
||||
However, Emacs can be started with the equivalent of either the
|
||||
option @code{--quick}, or @code{--debug-init} through a special
|
||||
preferences screen. Under Android 7.0 and later, this can be accessed
|
||||
through the Emacs ``app info'' page in the system settings program; on
|
||||
older systems, this is displayed as a separate icon on the desktop
|
||||
labeled ``Emacs options''.
|
||||
|
||||
Consult the manufacturer of your device for more details, as how to
|
||||
do this varies by device.
|
||||
|
||||
@cindex dumping, android
|
||||
The first time any given copy of Emacs starts on a device, it spends
|
||||
a while loading the preloaded Lisp files which normally come with
|
||||
Emacs. This produces a ``dump file'' (@pxref{Initial Options}) in the
|
||||
files directory, containing an identifier unique to that copy of
|
||||
Emacs.
|
||||
|
||||
The next time that same copy of Emacs starts up, it simply loads the
|
||||
data contained in that dump file, greatly reducing start up time.
|
||||
|
||||
If by some unforeseen circumstance the dump file is corrupted, Emacs
|
||||
can crash. If that happens, the dump file stored in the Emacs files
|
||||
directory can be erased through the preferences screen described
|
||||
above.
|
||||
|
||||
@cindex accessing Emacs directories, Android
|
||||
Emacs supports an alternative method of rescuing broken Emacs
|
||||
installations on Android 4.4 and later: Emacs exports a ``documents
|
||||
provider'' which accesses the contents of Emacs's home directory, that
|
||||
can then be accessed by any file manager program.
|
||||
|
||||
If you can find out how to open that documents provider in the file
|
||||
manager that comes with your device, you can rename, delete, or edit
|
||||
your initialization or dump files from there instead.
|
||||
|
||||
@node Android Software
|
||||
@section Installing Extra Software on Android
|
||||
@cindex installing extra software on Android
|
||||
@cindex installing Unix software on Android
|
||||
|
||||
Android includes an extremely limited set of Unix-like command line
|
||||
tools in a default installation. Several projects exist to argument
|
||||
this selection, providing options that range from improved
|
||||
reproductions of Unix command-line utilities to package repositories
|
||||
containing extensive collections of free GNU and Unix software.
|
||||
|
||||
@uref{http://busybox.net, Busybox} provides Unix utilities and
|
||||
limited replicas of certain popular GNU programs such as
|
||||
@command{wget} in a single statically-linked Linux binary, which is
|
||||
capable of running under Android.
|
||||
|
||||
@uref{https://termux.dev, Termux} provides a package manager based
|
||||
on the Debian project's @command{dpkg} system and a set of package
|
||||
repositories containing substantial amounts of free software for Unix
|
||||
systems, including compilers, debuggers, and runtimes for languages
|
||||
such as C, C++, Java, Python and Common Lisp. These packages are
|
||||
normally installed from within a purpose-built terminal emulator
|
||||
application, but Emacs can access them if it is built with the same
|
||||
application signing key as the Termux terminal emulator, and with its
|
||||
``shared user ID'' set to the package name of the terminal emulator
|
||||
program. The @file{java/INSTALL} within the Emacs distribution
|
||||
explains how to build Emacs in this fashion.
|
||||
|
||||
@uref{https://github.com/termux/termux-packages, termux-packages}
|
||||
provides the package definitions that are used by Termux to generate
|
||||
their package repositories, which may also be independently compiled
|
||||
for installation within Emacs's home directory.
|
||||
|
||||
In addition to the projects mentioned above, statically linked
|
||||
binaries for most Linux kernel-based systems can also be run on
|
||||
Android.
|
|
@ -684,6 +684,19 @@ cause trouble. For example, after renaming one or more files,
|
|||
@code{dired-undo} restores the original names in the Dired buffer,
|
||||
which gets the Dired buffer out of sync with the actual contents of
|
||||
the directory.
|
||||
|
||||
@item touchscreen-hold
|
||||
@kindex touchscreen-hold @r{(Dired)}
|
||||
@findex dired-click-to-select-mode
|
||||
@findex dired-enable-click-to-select-mode
|
||||
Enter a ``click to select'' mode, where using the mouse button
|
||||
@kbd{mouse-2} on a file name will cause its mark to be toggled. This
|
||||
mode is useful when performing file management using a touch screen
|
||||
device.
|
||||
|
||||
It is enabled when a ``hold'' gesture (@pxref{Touchscreens}) is
|
||||
detected over a file name, and is automatically disabled once a Dired
|
||||
command operates on the marked files.
|
||||
@end table
|
||||
|
||||
@node Operating on Files
|
||||
|
|
|
@ -223,7 +223,9 @@ Appendices
|
|||
* Antinews:: Information about Emacs version 28.
|
||||
* Mac OS / GNUstep:: Using Emacs under macOS and GNUstep.
|
||||
* Haiku:: Using Emacs on Haiku.
|
||||
* Android:: Using Emacs on Android.
|
||||
* Microsoft Windows:: Using Emacs on Microsoft Windows and MS-DOS.
|
||||
* Other Input Devices:: Using Emacs with other input devices.
|
||||
* Manifesto:: What's GNU? Gnu's Not Unix!
|
||||
|
||||
* Glossary:: Terms used in this manual.
|
||||
|
@ -1260,6 +1262,23 @@ Emacs and Haiku
|
|||
* Haiku Basics:: Basic Emacs usage and installation under Haiku.
|
||||
* Haiku Fonts:: The various options for displaying fonts on Haiku.
|
||||
|
||||
Emacs and Android
|
||||
|
||||
* What is Android?:: Preamble.
|
||||
* Android Startup:: Starting up Emacs on Android.
|
||||
* Android File System:: The Android file system.
|
||||
* Android Document Providers:: Accessing files from other programs.
|
||||
* Android Environment:: Running Emacs under Android.
|
||||
* Android Windowing:: The Android window system.
|
||||
* Android Fonts:: Font selection under Android.
|
||||
* Android Troubleshooting:: Dealing with problems.
|
||||
* Android Software:: Getting extra software.
|
||||
|
||||
Emacs and Unconventional Input Devices
|
||||
|
||||
* Touchscreens:: Using Emacs on touchscreens.
|
||||
* On-Screen Keyboards:: Using Emacs with virtual keyboards.
|
||||
|
||||
Emacs and Microsoft Windows/MS-DOS
|
||||
|
||||
* Windows Startup:: How to start Emacs on Windows.
|
||||
|
@ -1630,8 +1649,10 @@ Lisp programming.
|
|||
@include anti.texi
|
||||
@include macos.texi
|
||||
@include haiku.texi
|
||||
@include android.texi
|
||||
@c Includes msdos-xtra.
|
||||
@include msdos.texi
|
||||
@include input.texi
|
||||
@include gnu.texi
|
||||
@include glossary.texi
|
||||
@ifnottex
|
||||
|
|
|
@ -1333,6 +1333,21 @@ Parameters,,, elisp, The Emacs Lisp Reference Manual}. On macOS the
|
|||
tool bar is hidden when the frame is put into fullscreen, but can be
|
||||
displayed by moving the mouse pointer to the top of the screen.
|
||||
|
||||
@vindex modifier-bar-mode
|
||||
@findex modifier-bar-mode
|
||||
@cindex displaying modifier keys in the tool bar
|
||||
@cindex mode, Modifier Bar
|
||||
@cindex Modifier Bar
|
||||
Keyboards often lack one or more of the modifier keys that Emacs
|
||||
might want to use, making it difficult or impossible to input key
|
||||
sequences that contain them. Emacs can optionally display a list of
|
||||
buttons that act as substitutes for modifier keys within the tool bar;
|
||||
these buttons are also referred to as the ``modifier bar''. Clicking
|
||||
an icon within the modifier bar will cause a modifier key to be
|
||||
applied to the next keyboard event that is read. The modifier bar is
|
||||
displayed when the global minor mode @code{modifier-bar-mode} is
|
||||
enabled; to do so, type @kbd{M-x modifier-bar-mode}.
|
||||
|
||||
@node Tab Bars
|
||||
@section Tab Bars
|
||||
@cindex tab bar mode
|
||||
|
@ -1571,6 +1586,15 @@ the items that operate on the clicked tab. Dragging the tab with
|
|||
wheel scrolling switches to the next or previous tab. Holding down
|
||||
the @key{SHIFT} key during scrolling moves the tab to the left or right.
|
||||
|
||||
Touch screen input (@pxref{Other Input Devices}) can also be used to
|
||||
operate on tabs. Long-pressing (@pxref{Touchscreens}) a tab will
|
||||
display a context menu with items that operate on the tab that was
|
||||
pressed, and long-pressing the tab bar itself will display a context
|
||||
menu which lets you create and remove tabs; tapping a tab itself will
|
||||
result in that tab's window configuration being selected, and tapping
|
||||
a button on the tab bar will behave as if it was clicked with
|
||||
@kbd{mouse-1}.
|
||||
|
||||
@findex tab-bar-history-mode
|
||||
You can enable @code{tab-bar-history-mode} to remember window
|
||||
configurations used in every tab, and later restore them.
|
||||
|
|
179
doc/emacs/input.texi
Normal file
179
doc/emacs/input.texi
Normal file
|
@ -0,0 +1,179 @@
|
|||
@c This is part of the Emacs manual.
|
||||
@c Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
@c See file emacs.texi for copying conditions.
|
||||
@node Other Input Devices
|
||||
@appendix Emacs and Unconventional Input Devices
|
||||
@cindex other input devices
|
||||
|
||||
Emacs was originally developed with the assumption that its users
|
||||
have access to a desktop computer or computer terminal, with a
|
||||
keyboard and perhaps a suitable pointing device such as a mouse.
|
||||
|
||||
However, recent developments in the X Window System and operating
|
||||
systems such as Android mean that this assumption no longer holds
|
||||
true. Emacs supports input from various other kinds of input devices,
|
||||
which is detailed here.
|
||||
|
||||
@menu
|
||||
* Touchscreens:: Using Emacs on touchscreens.
|
||||
* On-Screen Keyboards:: Using Emacs with virtual keyboards.
|
||||
@end menu
|
||||
|
||||
@node Touchscreens
|
||||
@section Using Emacs on touchscreens
|
||||
@cindex touchscreen input
|
||||
|
||||
Touchscreen input works by pressing and moving tools (which include
|
||||
fingers and some pointing devices--styluses, for example) onto a frame
|
||||
in order to manipulate its contents.
|
||||
|
||||
When running under the X Window System or Android, Emacs
|
||||
automatically detects and maps the following sequences of movements
|
||||
(``gestures'') to common actions:
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
@cindex tapping, touchscreens
|
||||
``Tapping'', briefly placing and lifting a tool from the display,
|
||||
will result in Emacs selecting the window that was tapped, and
|
||||
executing any command bound to @code{mouse-1} at that location in the
|
||||
window. If the tap happened on top of a link (@pxref{Mouse
|
||||
References}), then Emacs will follow the link instead.
|
||||
|
||||
If a command bound to @code{down-mouse-1} is bound to the location
|
||||
where the tap took place, Emacs will execute that command as well.
|
||||
|
||||
@item
|
||||
@cindex scrolling, touchscreens
|
||||
``Scrolling'', meaning to place a tool on the display and move it up
|
||||
or down, will result in Emacs scrolling the window contents in the
|
||||
direction where the tool moves.
|
||||
|
||||
If the tool is moved left or right, Emacs additionally scrolls the
|
||||
window horizontally to follow (@pxref{Horizontal Scrolling}.)
|
||||
|
||||
@item
|
||||
@cindex dragging, touchscreens
|
||||
@cindex long-press, touchscreens
|
||||
``Dragging'', which is performing a @dfn{long-press} by placing a
|
||||
tool on the display and leaving it there for a while prior to moving
|
||||
the tool around will make Emacs set the point to where the tool was
|
||||
and begin selecting text under the tool as it moves around, as if
|
||||
@code{mouse-1} were to be held down. @xref{Mouse Commands}.
|
||||
|
||||
@vindex touch-screen-word-select
|
||||
@cindex word selection mode, touchscreens
|
||||
Some people find it difficult to position a tool accurately on a
|
||||
touch screen display, to the detriment of text selection. The user
|
||||
option @code{touch-screen-word-select} enables ``word selection
|
||||
mode'', causing dragging to select the complete word, not only the
|
||||
character containing the position of the tool.
|
||||
|
||||
@vindex touch-screen-extend-selection
|
||||
@cindex extending the selection, touchscreens
|
||||
Similarly, it may be difficult to select all of the text intended
|
||||
within a single gesture. If the user option
|
||||
@code{touch-screen-extend-selection} is enabled, taps on the locations
|
||||
of the point or the mark within a window will begin a new ``drag''
|
||||
gesture, where the region will be extended in the direction of any
|
||||
subsequent movement.
|
||||
|
||||
@vindex touch-screen-preview-select
|
||||
@cindex previewing the region during selection, touchscreens
|
||||
Difficulties in making accurate adjustments to the region can also
|
||||
be alleviated by indicating the position of the point relative to its
|
||||
containing line within the echo area, since the window cursor may be
|
||||
physically obscured by the tool. If
|
||||
@code{touch-screen-preview-select} is non-@code{nil}, the line
|
||||
containing point is displayed in the echo area (@pxref{Echo Area})
|
||||
during the motion of the tool, followed by another line indicating the
|
||||
position of point within the first line.
|
||||
@end itemize
|
||||
|
||||
@vindex touch-screen-delay
|
||||
By default, Emacs considers a tool as having been left on the
|
||||
display long enough to trigger a ``long-press'' after 0.7 seconds, but
|
||||
this can be changed by customizing the variable
|
||||
@code{touch-screen-delay}.
|
||||
|
||||
@node On-Screen Keyboards
|
||||
@section Using Emacs with virtual keyboards
|
||||
@cindex virtual keyboards
|
||||
@cindex on-screen keyboards
|
||||
|
||||
When there is no physical keyboard attached to a system, the
|
||||
windowing system typically provides an on-screen keyboard, more often
|
||||
known as a ``virtual keyboard'', containing rows of clickable buttons
|
||||
that send keyboard input to the application, much like a real keyboard
|
||||
would. This virtual keyboard is hidden by default, as it uses up
|
||||
valuable on-screen real estate, and must be opened once the program
|
||||
being used is ready to accept keyboard input.
|
||||
|
||||
Under the X Window System, the client that provides the on-screen
|
||||
keyboard typically detects when the application is ready to accept
|
||||
keyboard input through a set of complex heuristics, and automatically
|
||||
displays the keyboard when necessary.
|
||||
|
||||
On other systems such as Android, Emacs must tell the system when it
|
||||
is ready to accept keyboard input. Typically, this is done in
|
||||
response to a touchscreen ``tap'' gesture (@pxref{Touchscreens}), or
|
||||
once to the minibuffer becomes in use (@pxref{Minibuffer}.)
|
||||
|
||||
@vindex touch-screen-set-point-commands
|
||||
When a ``tap'' gesture results in a command being executed, Emacs
|
||||
checks to see whether or not the command is supposed to set the point
|
||||
by looking for it in the list @code{touch-screen-set-point-commands}.
|
||||
If it is, then Emacs looks up whether or not the text under the point
|
||||
is read-only; if not, it activates the on-screen keyboard, assuming
|
||||
that the user is about to enter text in to the current buffer.
|
||||
|
||||
@vindex touch-screen-display-keyboard
|
||||
The user option @code{touch-screen-display-keyboard} forces Emacs to
|
||||
always display the on screen keyboard; it may also be set buffer
|
||||
locally, which means that Emacs should always display the keyboard
|
||||
when the buffer is selected.
|
||||
|
||||
Emacs also provides a set of functions to show or hide the on-screen
|
||||
keyboard. For more details, @pxref{On-Screen Keyboards,,, elisp, The
|
||||
Emacs Lisp Reference Manual}.
|
||||
|
||||
@cindex quitting, without a keyboard
|
||||
Since it may not be possible for Emacs to display the on screen
|
||||
keyboard while it is executing a command, Emacs implements a feature
|
||||
on devices with only an on-screen keyboard, by which two rapid clicks
|
||||
of a hardware button that is always present on the device results in
|
||||
Emacs quitting. @xref{Quitting}.
|
||||
|
||||
@vindex x-quit-keysym
|
||||
Which button is used to do this depends on the window system in use:
|
||||
on X, it is defined in the variable @code{x-quit-keysym}, and on
|
||||
Android, it is always the volume down button.
|
||||
|
||||
@cindex text conversion, keyboards
|
||||
Most input methods designed to work with on-screen keyboards perform
|
||||
buffer edits differently from desktop input methods.
|
||||
|
||||
On a conventional desktop windowing system, an input method will
|
||||
simply display the contents of any on going character compositions on
|
||||
screen, and send the appropriate key events to Emacs after completion.
|
||||
|
||||
However, on screen keyboard input methods directly perform edits to
|
||||
the selected window of each frame; this is known as ``text
|
||||
conversion'', or ``string conversion'' under the X Window System.
|
||||
Emacs enables these input methods whenever the buffer local value of
|
||||
@code{text-conversion-style} is non-@code{nil}, normally inside
|
||||
derivatives of @code{text-mode} and @code{prog-mode}.
|
||||
|
||||
Text conversion is performed asynchronously whenever Emacs receives
|
||||
a request to perform the conversion from the input method, and Emacs
|
||||
is not currently reading a key sequence for which one prefix key has
|
||||
already been read (@pxref{Keys}.) After the conversion completes, a
|
||||
@code{text-conversion} event is sent. @xref{Misc Events,,, elisp, the
|
||||
Emacs Reference Manual}.
|
||||
|
||||
@vindex text-conversion-face
|
||||
If the input method needs to work on a region of the buffer, then
|
||||
the region becomes known as the ``composing region'' (or
|
||||
``preconversion region''.) The variable @code{text-conversion-face}
|
||||
describes whether or not to display the composing region in a specific
|
||||
face.
|
|
@ -642,6 +642,13 @@ to the window-local tab line of buffers, and clicking on the @kbd{x}
|
|||
icon of a tab deletes it. The mouse wheel on the tab line scrolls
|
||||
the tabs horizontally.
|
||||
|
||||
Touch screen input (@pxref{Other Input Devices}) can also be used to
|
||||
interact with the ``tab line''. Long-pressing (@pxref{Touchscreens})
|
||||
a tab will display a context menu with items that operate on the tab
|
||||
that was pressed; tapping a tab itself will result in switching to
|
||||
that tab's buffer, and tapping a button on the tab line will behave as
|
||||
if it was clicked with @kbd{mouse-1}.
|
||||
|
||||
Selecting the previous window-local tab is the same as typing @kbd{C-x
|
||||
@key{LEFT}} (@code{previous-buffer}), selecting the next tab is the
|
||||
same as @kbd{C-x @key{RIGHT}} (@code{next-buffer}). Both commands
|
||||
|
|
|
@ -2013,6 +2013,10 @@ the position of the finger when the event occurred.
|
|||
This event is sent when @var{point} is created by the user pressing a
|
||||
finger against the touchscreen.
|
||||
|
||||
Imaginary prefix keys are also affixed to these events
|
||||
@code{read-key-sequence} when they originate on top of a special part
|
||||
of a frame or window. @xref{Key Sequence Input}.
|
||||
|
||||
@cindex @code{touchscreen-update} event
|
||||
@item (touchscreen-update @var{points})
|
||||
This event is sent when a point on the touchscreen has changed
|
||||
|
@ -2029,8 +2033,172 @@ raised the finger from the touchscreen.
|
|||
intercepted by another program (such as the window manager), and Emacs
|
||||
should undo or avoid any editing commands that would otherwise result
|
||||
from the touch sequence.
|
||||
|
||||
Imaginary prefix keys are also affixed to these events
|
||||
@code{read-key-sequence} when they originate on top of a special part
|
||||
of a frame or window.
|
||||
@end table
|
||||
|
||||
If a touchpoint is pressed against the menu bar, then Emacs will not
|
||||
generate any corresponding @code{touchscreen-begin} or
|
||||
@code{touchscreen-end} events; instead, the menu bar may be displayed
|
||||
after @code{touchscreen-end} would have been delivered under other
|
||||
circumstances.
|
||||
|
||||
@cindex mouse emulation from touch screen events
|
||||
When no command is bound to @code{touchscreen-begin},
|
||||
@code{touchscreen-end} or @code{touchscreen-update}, Emacs calls a
|
||||
``key translation function'' (@pxref{Translation Keymaps}) to
|
||||
translate key sequences containing touch screen events into ordinary
|
||||
mouse events (@pxref{Mouse Events}.) Since Emacs doesn't support
|
||||
distinguishing events originating from separate mouse devices, it
|
||||
assumes that only one touchpoint is active while translation takes
|
||||
place; breaking this assumption may lead to unexpected behavior.
|
||||
|
||||
Emacs applies two different strategies for translating touch events
|
||||
into mouse events, contingent on factors such as the commands bound to
|
||||
keymaps that are active at the location of the
|
||||
@code{touchscreen-begin} event. If a command is bound to
|
||||
@code{down-mouse-1} at that location, the initial translation consists
|
||||
of a single @code{down-mouse-1} event, with subsequent
|
||||
@code{touchscreen-update} events translated to mouse motion events
|
||||
(@pxref{Motion Events}), and a final @code{touchscreen-end} event
|
||||
translated to a @code{mouse-1} or @code{drag-mouse-1} event (unless
|
||||
the @code{touchscreen-end} event indicates that the touch sequence has
|
||||
been intercepted by another program.) This is dubbed ``simple
|
||||
translation'', and produces a simple correspondence between touchpoint
|
||||
motion and mouse motion.
|
||||
|
||||
@cindex @code{ignored-mouse-command}, a symbol property
|
||||
However, some commands bound to
|
||||
@code{down-mouse-1}--@code{mouse-drag-region}, for example--either
|
||||
conflict with defined touch screen gestures (such as ``long-press to
|
||||
drag''), or with user expectations for touch input, and shouldn't
|
||||
subject the touch sequence to simple translation. If a command whose
|
||||
name contains the property (@pxref{Symbol Properties})
|
||||
@code{ignored-mouse-command} is encountered or there is no command
|
||||
bound to @code{down-mouse-1}, a more irregular form of translation
|
||||
takes place: here, Emacs processes touch screen gestures
|
||||
(@pxref{Touchscreens,,, emacs, The GNU Emacs Manual}) first, and
|
||||
finally attempts to translate touch screen events into mouse events if
|
||||
no gesture was detected prior to a closing @code{touchscreen-end}
|
||||
event (with its @var{canceled} parameter @code{nil}, as with simple
|
||||
translation) and a command is bound to @code{mouse-1} at the location
|
||||
of that event. Before generating the @code{mouse-1} event, point is
|
||||
also set to the location of the @code{touchscreen-end} event, and the
|
||||
window containing the position of that event is selected, as a
|
||||
compromise for packages which assume @code{mouse-drag-region} has
|
||||
already set point to the location of any mouse click and selected the
|
||||
window where it took place.
|
||||
|
||||
To prevent unwanted @code{mouse-1} events arriving after a mouse menu
|
||||
is dismissed (@pxref{Mouse Menus}), Emacs also avoids simple
|
||||
translation if @code{down-mouse-1} is bound to a keymap, making it a
|
||||
prefix key. In lieu of simple translation, it translates the closing
|
||||
@code{touchscreen-end} to a @code{down-mouse-1} event with the
|
||||
starting position of the touch sequence, consequentially displaying
|
||||
the mouse menu.
|
||||
|
||||
@cindex @code{mouse-1-menu-command}, a symbol property
|
||||
Since certain commands are also bound to @code{down-mouse-1} for the
|
||||
purpose of displaying pop-up menus, Emacs additionally behaves as
|
||||
illustrated in the last paragraph if @code{down-mouse-1} is bound to a
|
||||
command whose name has the property @code{mouse-1-menu-command}.
|
||||
|
||||
@cindex touchscreen gesture events
|
||||
If touch gestures are detected during translation, one of the
|
||||
following input events may be generated:
|
||||
|
||||
@table @code
|
||||
@cindex @code{touchscreen-scroll} event
|
||||
@item (touchscreen-scroll @var{window} @var{dx} @var{dy})
|
||||
If a ``scrolling'' gesture is detected during the translation process,
|
||||
each subsequent @code{touchscreen-update} event is translated to a
|
||||
@code{touchscreen-scroll} event, where @var{dx} and @var{dy} specify,
|
||||
in pixels, the relative motion of the touchpoint from the position of
|
||||
the @code{touchscreen-begin} event that started the sequence or the
|
||||
last @code{touchscreen-scroll} event, whichever came later.
|
||||
|
||||
@cindex @code{touchscreen-hold} event
|
||||
@item (touchscreen-hold @var{posn})
|
||||
If the single active touchpoint remains stationary for more than
|
||||
@code{touch-screen-delay} seconds after a @code{touchscreen-begin} is
|
||||
generated, a ``long-press'' gesture is detected during the translation
|
||||
process, and a @code{touchscreen-hold} event is sent, with @var{posn}
|
||||
set to a mouse position list containing the position of the
|
||||
@code{touchscreen-begin} event.
|
||||
|
||||
@cindex @code{touchscreen-drag} event
|
||||
@item (touchscreen-drag @var{posn})
|
||||
If a ``long-press'' gesture is detected while translating the current
|
||||
touch sequence or ``drag-to-select'' is being resumed as a result of
|
||||
the @code{touch-screen-extend-selection} user option, a
|
||||
@code{touchscreen-drag} event is sent upon each subsequent
|
||||
@code{touchscreen-update} event with @var{posn} set to the new
|
||||
position of the touchpoint.
|
||||
|
||||
@cindex @code{touchscreen-restart-drag} event
|
||||
@item (touchscreen-restart-drag @var{posn})
|
||||
This event is sent upon the start of a touch sequence resulting in the
|
||||
continuation of a ``drag-to-select'' gesture (subject to the
|
||||
aformentioned user option) with @var{posn} set to the position list of
|
||||
the initial @code{touchscreen-begin} event within that touch sequence.
|
||||
@end table
|
||||
|
||||
@cindex handling touch screen events
|
||||
@cindex tap and drag, touch screen gestures
|
||||
Several functions are provided for Lisp programs that handle touch
|
||||
screen events. The intended use of the first two functions described
|
||||
below is from commands bound directly to @code{touchscreen-begin}
|
||||
events; they allow responding to commonly used touch screen gestures
|
||||
separately from mouse event translation.
|
||||
|
||||
@defun touch-screen-track-tap event &optional update data
|
||||
This function is used to track a single ``tap'' gesture originating
|
||||
from the @code{touchscreen-begin} event @var{event}, often used to
|
||||
set the point or to activate a button. It waits for a
|
||||
@code{touchscreen-end} event with the same touch identifier to arrive,
|
||||
at which point it returns @code{t}, signifying the end of the gesture.
|
||||
|
||||
If a @code{touchscreen-update} event arrives in the mean time and
|
||||
contains at least one touchpoint with the same identifier as in
|
||||
@var{event}, the function @var{update} is called with two arguments,
|
||||
the list of touchpoints in that @code{touchscreen-update} event, and
|
||||
@var{data}.
|
||||
|
||||
If any other event arrives in the mean time, @code{nil} is returned.
|
||||
The caller should not perform any action in that case.
|
||||
@end defun
|
||||
|
||||
@defun touch-screen-track-drag event update &optional data
|
||||
This function is used to track a single ``drag'' gesture originating
|
||||
from the @code{touchscreen-begin} event @code{event}.
|
||||
|
||||
It behaves like @code{touch-screen-track-tap}, except that it returns
|
||||
@code{no-drag} and refrains from calling @var{update} if the
|
||||
touchpoint in @code{event} did not move far enough (by default, 5
|
||||
pixels from its position in @code{event}) to qualify as an actual
|
||||
drag.
|
||||
@end defun
|
||||
|
||||
In addition to those two functions, a function is provided for
|
||||
commands bound to some types of events generated through mouse event
|
||||
translation to prevent unwanted events from being generated after it
|
||||
is called.
|
||||
|
||||
@defun touch-screen-inhibit-drag
|
||||
This function inhibits the generation of @code{touchscreen-drag}
|
||||
events during mouse event translation for the duration of the touch
|
||||
sequence being translated after it is called. It must be called from
|
||||
a command which is bound to a @code{touchscreen-hold} or
|
||||
@code{touchscreen-drag} event, and signals an error otherwise.
|
||||
|
||||
Since this function can only be called after a gesture is already
|
||||
recognized during mouse event translation, no mouse events will be
|
||||
generated from touch events constituting the previously mentioned
|
||||
touch sequence after it is called.
|
||||
@end defun
|
||||
|
||||
@node Focus Events
|
||||
@subsection Focus Events
|
||||
@cindex focus event
|
||||
|
@ -2167,6 +2335,65 @@ the buffer in which the xwidget will be displayed, using
|
|||
A few other event types represent occurrences within the system.
|
||||
|
||||
@table @code
|
||||
@cindex @code{text-conversion} event
|
||||
@item text-conversion
|
||||
This kind of event is sent @strong{after} a system-wide input method
|
||||
performs an edit to one or more buffers.
|
||||
|
||||
@vindex text-conversion-edits
|
||||
Once the event is sent, the input method may already have made changes
|
||||
to multiple buffers inside many different frames. To determine which
|
||||
buffers have been changed, and what edits have been made to them, use
|
||||
the variable @code{text-conversion-edits}, which is set prior to each
|
||||
@code{text-conversion} event being sent; it is a list of the form:
|
||||
|
||||
@example
|
||||
@w{@code{((@var{buffer} @var{beg} @var{end} @var{ephemeral}) ...)}}
|
||||
@end example
|
||||
|
||||
Where @var{ephemeral} is the buffer which was modified, @var{beg} and
|
||||
@var{end} are markers set to the positions of the edit at the time it
|
||||
was completed, and @var{ephemeral} is either a string, containing any
|
||||
text which was inserted (or any text before point which was deleted),
|
||||
@code{t}, meaning that the edit is a temporary edit made by the input
|
||||
method, or @code{nil}, meaning that some text was deleted after point.
|
||||
|
||||
@vindex text-conversion-style
|
||||
Whether or not this event is sent depends on the value of the
|
||||
buffer-local variable @code{text-conversion-style}, which determines
|
||||
how an input method that wishes to make edits to buffer contents will
|
||||
behave.
|
||||
|
||||
This variable can have one of three values:
|
||||
|
||||
@table @code
|
||||
@item nil
|
||||
This means that the input method will be disabled entirely, and key
|
||||
events will be sent instead of text conversion events.
|
||||
|
||||
@item action
|
||||
This means that the input method will be enabled, but @key{RET} will
|
||||
be sent whenever the input method wants to insert a new line.
|
||||
|
||||
@item t
|
||||
This, or any other value, means that the input method will be enabled
|
||||
and make edits followed by @code{text-conversion} events.
|
||||
@end table
|
||||
|
||||
@findex set-text-conversion-style
|
||||
Changes to the value of this variable will only take effect upon the
|
||||
next redisplay after the buffer becomes the selected buffer of a
|
||||
frame. If you need to disable text conversion in a way that takes
|
||||
immediate effect, call the function @code{set-text-conversion-style}
|
||||
instead. This has the potential to lock up the input method for a
|
||||
significant amount of time, and should be used with care.
|
||||
|
||||
@vindex disable-inhibit-text-conversion
|
||||
In addition, text conversion is automatically disabled after a prefix
|
||||
key is read by the command loop or @code{read-key-sequence}. This can
|
||||
be disabled by setting or binding the variable
|
||||
@code{disable-inhibit-text-conversion} to a non-@code{nil} value.
|
||||
|
||||
@cindex @code{delete-frame} event
|
||||
@item (delete-frame (@var{frame}))
|
||||
This kind of event indicates that the user gave the window manager
|
||||
|
@ -2946,7 +3173,7 @@ debugging terminal input.
|
|||
@code{read-key-sequence}. Lisp programs can also call this function;
|
||||
for example, @code{describe-key} uses it to read the key to describe.
|
||||
|
||||
@defun read-key-sequence prompt &optional continue-echo dont-downcase-last switch-frame-ok command-loop
|
||||
@defun read-key-sequence prompt &optional continue-echo dont-downcase-last switch-frame-ok command-loop disable-text-conversion
|
||||
This function reads a key sequence and returns it as a string or
|
||||
vector. It keeps reading events until it has accumulated a complete key
|
||||
sequence; that is, enough to specify a non-prefix command using the
|
||||
|
@ -2986,6 +3213,12 @@ key sequence is being read by something that will read commands one
|
|||
after another. It should be @code{nil} if the caller will read just
|
||||
one key sequence.
|
||||
|
||||
The argument @var{disable-text-conversion}, if non-@code{nil}, means
|
||||
that system input methods will not directly perform edits to buffer
|
||||
text while this key sequence is being read; user input will always
|
||||
generated individual key events instead. @xref{Misc Events} for more
|
||||
about text conversion.
|
||||
|
||||
In the following example, Emacs displays the prompt @samp{?} in the
|
||||
echo area, and then the user types @kbd{C-x C-f}.
|
||||
|
||||
|
@ -3006,7 +3239,7 @@ typed while reading with this function works like any other character,
|
|||
and does not set @code{quit-flag}. @xref{Quitting}.
|
||||
@end defun
|
||||
|
||||
@defun read-key-sequence-vector prompt &optional continue-echo dont-downcase-last switch-frame-ok command-loop
|
||||
@defun read-key-sequence-vector prompt &optional continue-echo dont-downcase-last switch-frame-ok command-loop disable-text-conversion
|
||||
This is like @code{read-key-sequence} except that it always
|
||||
returns the key sequence as a vector, never as a string.
|
||||
@xref{Strings of Events}.
|
||||
|
@ -3054,19 +3287,22 @@ with any other events.
|
|||
@cindex @code{right-divider}, prefix key
|
||||
@cindex @code{bottom-divider}, prefix key
|
||||
@cindex mouse events, in special parts of window or frame
|
||||
When mouse events occur in special parts of a window or frame, such as a mode
|
||||
@cindex touch screen events, in special parts of window or frame
|
||||
When mouse or @code{touchscreen-begin} and @code{touchscreen-end}
|
||||
events occur in special parts of a window or frame, such as a mode
|
||||
line or a scroll bar, the event type shows nothing special---it is the
|
||||
same symbol that would normally represent that combination of mouse
|
||||
button and modifier keys. The information about the window part is kept
|
||||
elsewhere in the event---in the coordinates. But
|
||||
button and modifier keys. The information about the window part is
|
||||
kept elsewhere in the event---in the coordinates. But
|
||||
@code{read-key-sequence} translates this information into imaginary
|
||||
prefix keys, all of which are symbols: @code{tab-line}, @code{header-line},
|
||||
@code{horizontal-scroll-bar}, @code{menu-bar}, @code{tab-bar}, @code{mode-line},
|
||||
@code{vertical-line}, @code{vertical-scroll-bar}, @code{left-margin},
|
||||
@code{right-margin}, @code{left-fringe}, @code{right-fringe},
|
||||
@code{right-divider}, and @code{bottom-divider}. You can define meanings for
|
||||
mouse clicks in special window parts by defining key sequences using these
|
||||
imaginary prefix keys.
|
||||
prefix keys, all of which are symbols: @code{tab-line},
|
||||
@code{header-line}, @code{horizontal-scroll-bar}, @code{menu-bar},
|
||||
@code{tab-bar}, @code{mode-line}, @code{vertical-line},
|
||||
@code{vertical-scroll-bar}, @code{left-margin}, @code{right-margin},
|
||||
@code{left-fringe}, @code{right-fringe}, @code{right-divider}, and
|
||||
@code{bottom-divider}. You can define meanings for mouse clicks in
|
||||
special window parts by defining key sequences using these imaginary
|
||||
prefix keys.
|
||||
|
||||
For example, if you call @code{read-key-sequence} and then click the
|
||||
mouse on the window's mode line, you get two events, like this:
|
||||
|
|
|
@ -2942,8 +2942,9 @@ apply to. Here are the possible values of @var{characteristic}:
|
|||
The kind of window system the terminal uses---either @code{graphic}
|
||||
(any graphics-capable display), @code{x}, @code{pc} (for the MS-DOS
|
||||
console), @code{w32} (for MS Windows 9X/NT/2K/XP), @code{haiku} (for
|
||||
Haiku), @code{pgtk} (for pure GTK), or @code{tty} (a non-graphics-capable
|
||||
display). @xref{Window Systems, window-system}.
|
||||
Haiku), @code{pgtk} (for pure GTK), @code{android} (for Android), or
|
||||
@code{tty} (a non-graphics-capable display). @xref{Window Systems,
|
||||
window-system}.
|
||||
|
||||
@item class
|
||||
What kinds of colors the terminal supports---either @code{color},
|
||||
|
@ -8874,6 +8875,8 @@ Emacs is displaying the frame using MS-DOS direct screen writes.
|
|||
Emacs is displaying the frame using the Application Kit on Haiku.
|
||||
@item pgtk
|
||||
Emacs is displaying the frame using pure GTK facilities.
|
||||
@item android
|
||||
Emacs is displaying the frame on Android.
|
||||
@item nil
|
||||
Emacs is displaying the frame on a character-based terminal.
|
||||
@end table
|
||||
|
|
|
@ -1139,6 +1139,7 @@ Frames
|
|||
* Dialog Boxes:: Displaying a box to ask yes or no.
|
||||
* Pointer Shape:: Specifying the shape of the mouse pointer.
|
||||
* Window System Selections::Transferring text to and from other X clients.
|
||||
* Accessing Selections:: The multiple different kinds of selections.
|
||||
* Yanking Media:: Yanking things that aren't plain text.
|
||||
* Drag and Drop:: Internals of Drag-and-Drop implementation.
|
||||
* Color Names:: Getting the definitions of color names.
|
||||
|
|
|
@ -104,9 +104,11 @@ window of another Emacs frame. @xref{Child Frames}.
|
|||
* Mouse Tracking:: Getting events that say when the mouse moves.
|
||||
* Mouse Position:: Asking where the mouse is, or moving it.
|
||||
* Pop-Up Menus:: Displaying a menu for the user to select from.
|
||||
* On-Screen Keyboards:: Displaying the virtual keyboard.
|
||||
* Dialog Boxes:: Displaying a box to ask yes or no.
|
||||
* Pointer Shape:: Specifying the shape of the mouse pointer.
|
||||
* Window System Selections:: Transferring text to and from other X clients.
|
||||
* Accessing Selections:: The multiple different kinds of selections.
|
||||
* Yanking Media:: Yanking things that aren't plain text.
|
||||
* Drag and Drop:: Internals of Drag-and-Drop implementation.
|
||||
* Color Names:: Getting the definitions of color names.
|
||||
|
@ -700,7 +702,7 @@ The position of the top left corner of the native frame specifies the
|
|||
indicate that position for the various builds:
|
||||
|
||||
@itemize @w{}
|
||||
@item (1) non-toolkit, Haiku, and terminal frames
|
||||
@item (1) non-toolkit, Android, Haiku, and terminal frames
|
||||
|
||||
@item (2) Lucid, Motif, and MS-Windows frames
|
||||
|
||||
|
@ -2408,6 +2410,7 @@ engine), and @code{harfbuzz} (font driver for OTF and TTF fonts with
|
|||
HarfBuzz text shaping) (@pxref{Windows Fonts,,, emacs, The GNU Emacs
|
||||
Manual}). The @code{harfbuzz} driver is similarly recommended. On
|
||||
Haiku, there can be several font drivers (@pxref{Haiku Fonts,,, emacs,
|
||||
The GNU Emacs Manual}), as on Android (@pxref{Android Fonts,,, emacs,
|
||||
The GNU Emacs Manual}).
|
||||
|
||||
On other systems, there is only one available font backend, so it does
|
||||
|
@ -3753,9 +3756,9 @@ This function displays a pop-up menu and returns an indication of
|
|||
what selection the user makes.
|
||||
|
||||
The argument @var{position} specifies where on the screen to put the
|
||||
top left corner of the menu. It can be either a mouse button event
|
||||
(which says to put the menu where the user actuated the button) or a
|
||||
list of this form:
|
||||
top left corner of the menu. It can be either a mouse button or
|
||||
@code{touchscreen-begin} event (which says to put the menu where the
|
||||
user actuated the button) or a list of this form:
|
||||
|
||||
@example
|
||||
((@var{xoffset} @var{yoffset}) @var{window})
|
||||
|
@ -3840,6 +3843,30 @@ keymap. It won't be called if @code{x-popup-menu} returns for some
|
|||
other reason without displaying a pop-up menu.
|
||||
@end defvar
|
||||
|
||||
@node On-Screen Keyboards
|
||||
@section On-Screen Keyboards
|
||||
|
||||
An on-screen keyboard is a special kind of pop up provided by the
|
||||
system, with rows of clickable buttons that act as a real keyboard.
|
||||
|
||||
On certain systems (@pxref{On-Screen Keyboards,,,emacs, The Emacs
|
||||
Manual}), Emacs is supposed to display and hide the on screen keyboard
|
||||
depending on whether or not the user is about to type something.
|
||||
|
||||
@defun frame-toggle-on-screen-keyboard frame hide
|
||||
This function displays or hides the on-screen keyboard on behalf of
|
||||
the frame @var{frame}. If @var{hide} is non-@code{nil}, then the
|
||||
on-screen keyboard is hidden; otherwise, it is displayed.
|
||||
|
||||
It returns whether or not the on screen keyboard @strong{may} have
|
||||
been displayed, which should be used to determine whether or not to
|
||||
hide the on-screen keyboard later.
|
||||
|
||||
This has no effect if the system automatically detects when to display
|
||||
the on-screen keyboard, or when it does not provide any on-screen
|
||||
keyboard.
|
||||
@end defun
|
||||
|
||||
@node Dialog Boxes
|
||||
@section Dialog Boxes
|
||||
@cindex dialog boxes
|
||||
|
@ -4047,6 +4074,542 @@ For backward compatibility, there are obsolete aliases
|
|||
names of @code{gui-get-selection} and @code{gui-set-selection} before
|
||||
Emacs 25.1.
|
||||
|
||||
@node Accessing Selections
|
||||
@section Accessing Selections
|
||||
|
||||
@code{gui-get-selection} is able to retrieve multiple different
|
||||
kinds of selection data from any number of selections. However, the
|
||||
data types and selections that Emacs understands is not precisely
|
||||
specified and differs depending on the window system on which Emacs is
|
||||
running.
|
||||
|
||||
At the same time, @code{gui-set-selection} hides a great deal of
|
||||
complexity behind its back, at least on some systems: its @var{data}
|
||||
argument need not be a string, but is actually given verbatim to
|
||||
system specific code.
|
||||
|
||||
Emacs's implementation of selections is most complete on the X
|
||||
Window System. This is both an artifact of history (X was the first
|
||||
window system supported by Emacs) and one of technical reasons:
|
||||
instead of using selections only to transfer text and multimedia
|
||||
content between clients, X uses selections as a general inter-client
|
||||
communication system, leading to a great proliferation of selection
|
||||
data types.
|
||||
|
||||
Even more confusingly, X also supports another inter-client
|
||||
communication mechanism: the Inter-Client Exchange. However, ICE is
|
||||
only used by Emacs to communicate with session managers, and is a
|
||||
separate topic.
|
||||
|
||||
@menu
|
||||
* X Selections:: Selection data types (and more) on X.
|
||||
* Other Selections:: How they work on other window systems.
|
||||
@end menu
|
||||
|
||||
@node X Selections
|
||||
@subsection X Selections
|
||||
|
||||
X refrains from defining fixed data types for selection data, or a
|
||||
fixed number of selections. Selections are instead identified by X
|
||||
``atoms'', which are unique 29-bit identifiers issued by the X server
|
||||
for a corresponding name. In Emacs, you can simply write a symbol
|
||||
with the name of the atom, and Emacs will transparently request these
|
||||
identifiers where necessary.
|
||||
|
||||
When a program ``sets'' a selection under X, it actually makes
|
||||
itself the ``owner'' of the selection---the X server will then deliver
|
||||
selection requests to the program, which is obliged to respond to the
|
||||
requesting client with the selection data.
|
||||
|
||||
Similarly, a program does not ``get'' selection data from the X
|
||||
server. Instead, its selection requests are sent to the client with
|
||||
the window which last took ownership over the selection, which then
|
||||
replies with the requested data.
|
||||
|
||||
Each selection request contains three parameters:
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
The window which requested the selection; this is used to identify the
|
||||
@c Not a typo: X spells ``requestor'' with an o.
|
||||
requesting program, otherwise known as the @dfn{requestor}.
|
||||
|
||||
@item
|
||||
An atom identifying the ``target'' to which the owner should convert
|
||||
the selection. It is easiest to think of the conversion target as the
|
||||
kind of data that the requestor wants: in selection requests made by
|
||||
Emacs, the target is determined by the @dfn{type} argument to
|
||||
@code{gui-get-selection}.
|
||||
|
||||
@item
|
||||
A 32-bit timestamp containing the X server time at which the requestor
|
||||
last obtained input.
|
||||
@end itemize
|
||||
|
||||
The selection owner responds by tranferring to the requestor a
|
||||
series of bytes, 16 bit words, or 32 bit words, along with another
|
||||
atom identifying the type of those words. After requesting a
|
||||
selection, Emacs then applies its own interpretation of the data
|
||||
format and data type to convert the data transferred by the selection
|
||||
owner to a Lisp representation, which @code{gui-get-selection}
|
||||
returns.
|
||||
|
||||
By default, Emacs converts selection data consisting of any series
|
||||
of bytes to a unibyte string containing those bytes, selection data
|
||||
consisting of a single 16-bit or 32-bit word as an unsigned number,
|
||||
and selection data consisting of multiple such words as a vector of
|
||||
unsigned numbers. However, Emacs applies special treatment for
|
||||
several selection data types:
|
||||
|
||||
@table @code
|
||||
@item INTEGER
|
||||
16-bit or 32-bit words of this type are treated as signed integers,
|
||||
instead of unsigned ones. If there are multiple words in the
|
||||
selection data, a vector is returned; otherwise, the integer is
|
||||
returned by itself.
|
||||
|
||||
@item ATOM
|
||||
32-bit words of this type are treated as X atoms, and returned (either
|
||||
alone or as vectors) as Lisp symbols containing the names they
|
||||
identify. Invalid atoms are returned as @code{nil}.
|
||||
|
||||
@item COMPOUND_TEXT
|
||||
@item UTF8_STRING
|
||||
@item STRING
|
||||
Unibyte strings returned for these data types will have a single
|
||||
@code{foreign-selection} text property set to a symbol with the type
|
||||
of the selection data.
|
||||
@end table
|
||||
|
||||
Each selection owner must return at least two selection targets:
|
||||
@code{TARGETS}, which returns a number of atoms describing the
|
||||
selection targets that the owner supports, and @code{MULTIPLE}, used
|
||||
for internal purposes by X clients. A selection owner may support any
|
||||
number of other targets, some of which may be standardized by the X
|
||||
Consortium's
|
||||
@url{http://x.org/releases/X11R7.6/doc/xorg-docs/specs/ICCCM/icccm.html,
|
||||
Inter-Client Communication Conventions Manual}, while others, such as
|
||||
@code{UTF8_STRING}, were supposed to be standardized by the XFree86
|
||||
Project, which unfortunately did not happen.
|
||||
|
||||
Requests for a given selection target may, by convention, return
|
||||
data in a specific type, or it may return data in one of several
|
||||
types, whichever is most convenient for the selection owner; the
|
||||
latter type of selection target is dubbed a @dfn{polymorphic target}.
|
||||
A selection target may also return no data at all: by convention, the
|
||||
selection owner performs some action a side effect upon responding to
|
||||
a selection request with that target, and as such these targets are
|
||||
referred to as @dfn{side-effect targets}.
|
||||
|
||||
Here are some selection targets which behave in a reasonably
|
||||
standard manner when used with the @code{CLIPBOARD}, @code{PRIMARY},
|
||||
or @code{SECONDARY} selections.
|
||||
|
||||
@table @code
|
||||
@item ADOBE_PORTABLE_DOCUMENT_FORMAT
|
||||
This target returns data in Adobe System's ``Portable Document
|
||||
Format'' format, as a string.
|
||||
|
||||
@item APPLE_PICT
|
||||
This target returns data in the ``PICT'' image format used on
|
||||
Macintosh computers, as a string.
|
||||
|
||||
@item BACKGROUND
|
||||
@item BITMAP
|
||||
@item COLORMAP
|
||||
@item FOREGROUND
|
||||
Together, these four targets return integer data necessary to make use
|
||||
of a bitmap image stored on the X server: the pixel value of the
|
||||
bitmap's background color, the X identifier of the bitmap, the
|
||||
colormap inside which the background and foreground are allocated, and
|
||||
the pixel value of the bitmap's foreground color.
|
||||
|
||||
@item CHARACTER_POSITION
|
||||
This target returns two unsigned 32-bit integers of type @code{SPAN}
|
||||
describing the start and end positions of the selection data in the
|
||||
text field containing it, in bytes.
|
||||
|
||||
@item COMPOUND_TEXT
|
||||
This target returns a string of type @code{COMPOUND_TEXT} in the X
|
||||
Consortium's multi-byte text encoding system.
|
||||
|
||||
@item DELETE
|
||||
This target returns nothing, but as a side-effect deletes the
|
||||
selection contents from any text field containing them.
|
||||
|
||||
@item DRAWABLE
|
||||
@item PIXMAP
|
||||
This target returns a list of unsigned 32-bit integers, each of which
|
||||
corresponds to an X server drawable or pixmap.
|
||||
|
||||
@item ENCAPSULATED_POSTSCRIPT
|
||||
@item _ADOBE_EPS
|
||||
This target returns a string containing encapsulated Postscript code.
|
||||
|
||||
@item FILE_NAME
|
||||
This target returns a string containing one or more file names,
|
||||
separated by NULL characters.
|
||||
|
||||
@item HOST_NAME
|
||||
This target returns a string containing the fully-qualified domain
|
||||
name of the machine on which the selection owner is running.
|
||||
|
||||
@item USER
|
||||
This target returns a string containing the user name of the machine
|
||||
on which the selection owner is running.
|
||||
|
||||
@item LENGTH
|
||||
This target returns an unsigned 32-bit or 16-bit integer containing
|
||||
the length of the selection data.
|
||||
|
||||
@item LINE_NUMBER
|
||||
This target returns two unsigned 32-bit integers of type @code{SPAN}
|
||||
describing the line numbers corresponding to the start and end
|
||||
positions of the selection data in the text field containing it.
|
||||
|
||||
@item MODULE
|
||||
This target returns the name of any function containing the selection
|
||||
data. It is mainly used by text editors.
|
||||
|
||||
@item STRING
|
||||
This target returns the selection data as a string of type
|
||||
@code{STRING}, encoded in ISO Latin-1 format, with Unix newline
|
||||
characters.
|
||||
|
||||
@item C_STRING
|
||||
This target returns the selection data as a ``C string''. This has
|
||||
been interpreted as meaning the raw selection data in whatever
|
||||
encoding used by the owner, either terminated with a NULL byte or not
|
||||
at all, or an ASCII string which may or may not be terminated.
|
||||
|
||||
@item UTF8_STRING
|
||||
This returns the selection data as a string of type
|
||||
@code{UTF8_STRING}, encoded in UTF-8, with unspecified EOL format.
|
||||
|
||||
@item TIMESTAMP
|
||||
This target returns the X server time at which the selection owner
|
||||
took ownership over the selection as a 16-bit or 32-bit word of type
|
||||
@code{CARDINAL}.
|
||||
|
||||
@item TEXT
|
||||
This polymorphic target returns selection data as a string, either
|
||||
@code{COMPOUND_TEXT}, @code{STRING}, @code{C_STRING}, or
|
||||
@code{UTF8_STRING}, whichever data type is convenient for the
|
||||
selection owner.
|
||||
@end table
|
||||
|
||||
When a request for the targets @code{STRING}, @code{COMPOUND_TEXT},
|
||||
or @code{UTF8_STRING} is made using the function
|
||||
@code{gui-get-selection}, and neither @code{selection-coding-system}
|
||||
nor @code{next-selection-coding-system} are set, the returned strings
|
||||
are additionally decoded using the appropriate coding system for those
|
||||
data types: @code{iso-8859-1}, @code{compound-text-with-extensions}
|
||||
and @code{utf-8} respectively.
|
||||
|
||||
In addition to the targets specified above (and the many targets
|
||||
used by various programs for their own purposes), several popular
|
||||
programs and toolkits have decided to define selection data types of
|
||||
their own, without consulting the appropriate X standards bodies.
|
||||
These targets are usually named after MIME types, such as
|
||||
@code{text/html} or @code{image/jpeg}, and have been known to contain:
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
Unterminated, newline terminated, or NULL character terminated file
|
||||
names of an image or text file.
|
||||
|
||||
@item
|
||||
Image or text data in the appropriate format.
|
||||
|
||||
@item
|
||||
@code{file://} URIs (or possibly newline or NUL terminated lists of
|
||||
URIs) leading to files in the appropriate format.
|
||||
@end itemize
|
||||
|
||||
These selection targets were first used by Netscape, but are now
|
||||
found in all kinds of programs, especially those based on recent
|
||||
versions of the GTK+ or Qt toolkits.
|
||||
|
||||
Emacs is also capable of acting as a selection owner. When
|
||||
@code{gui-set-selection} is called, the selection data specified is
|
||||
not transferred to the X server; instead, Emacs records it internally
|
||||
and obtains ownership of the selection.
|
||||
|
||||
@defvar selection-converter-alist
|
||||
Alist of selection targets to ``selection converter'' functions.
|
||||
When a selection request is received, Emacs looks up the selection
|
||||
converter associated with the requested selection target.
|
||||
|
||||
The selection converter is called with three arguments: the symbol
|
||||
corresponding to the atom identifying the selection being requested,
|
||||
the selection target that is being requested, and the value set with
|
||||
@code{gui-set-selection}. The value which it returns is either a cons
|
||||
of a symbol specifying the data type and a number, symbol, or a vector
|
||||
of numbers or symbols, or its cdr by itself.
|
||||
|
||||
If the value is the special symbol @code{NULL}, the data type is set
|
||||
to @code{NULL}, and no data is returned to the requestor.
|
||||
|
||||
If the value is a string, it must be a unibyte string; should no
|
||||
data type be explicitly specified, the data is transferred to the
|
||||
requestor with the type @code{STRING}.
|
||||
|
||||
If the value is a symbol, its ``atom'' is retrieved, and it is
|
||||
transferred to the requestor as a 32-bit value---if no data type was
|
||||
specified, its type is @code{ATOM}.
|
||||
|
||||
If the value is a number between @code{-32769} and @code{32768}, it
|
||||
is transferred to the requestor as a 16 bit value---if no data type
|
||||
was specified, its type is @code{INTEGER}.
|
||||
|
||||
If the value is any other number, it is returned as a 32 bit value.
|
||||
Even if the number returned is unsigned, the requestor will treat
|
||||
words of type @code{INTEGER} as signed. To return an unsigned value,
|
||||
specify the type @code{CARDINAL} instead.
|
||||
|
||||
If the value is a vector of symbols or numbers, it is returned as a
|
||||
list of multiple atoms or numbers. The data type returned by default
|
||||
is determined by that of its first element.
|
||||
@end defvar
|
||||
|
||||
By default, Emacs is configured with selection converters for the
|
||||
following selection targets:
|
||||
|
||||
@table @code
|
||||
@item TEXT
|
||||
This selection converter returns selection data as:
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
A string of type @code{C_STRING}, if the selection contents contain no
|
||||
multibyte characters, or contains 8-bit characters with all 8 bits
|
||||
set.
|
||||
|
||||
@item
|
||||
A string of type @code{STRING}, if the selection contents can be
|
||||
represented as ISO-Latin-1 text.
|
||||
|
||||
@item
|
||||
A string of type @code{COMPOUND_TEXT}, if the selection contents can
|
||||
be encoded in the X Consortium's Compound Text Encoding, and
|
||||
@code{selection-coding-system} or @code{next-selection-coding-system}
|
||||
is set to a coding system whose @code{:mime-charset} property is
|
||||
@code{x-ctext}.
|
||||
|
||||
@item
|
||||
A string of type @code{UTF8_STRING} otherwise.
|
||||
@end itemize
|
||||
|
||||
@item COMPOUND_TEXT
|
||||
This selection converter returns selection data as a string of type
|
||||
@code{COMPOUND_TEXT}.
|
||||
|
||||
@item STRING
|
||||
This selection converter returns selection data as a string of type
|
||||
@code{STRING}, encoded in ISO-Latin-1 format.
|
||||
|
||||
@item UTF8_STRING
|
||||
This selection converter returns selection data in UTF-8 format.
|
||||
|
||||
@item text/plain
|
||||
@item text/plain;charset=utf-8
|
||||
@item text/uri-list
|
||||
@item text/x-xdnd-username
|
||||
@item XmTRANSFER_SUCCESS
|
||||
@item XmTRANSFER_FAILURE
|
||||
@item FILE
|
||||
@item _DT_NETFILE
|
||||
These selection converters are used for internal purposes during
|
||||
drag-and-drop operations and are not available for selections other
|
||||
than @code{XdndSelection}.
|
||||
|
||||
@item TARGETS
|
||||
This selection converter returns a list of atoms, one for each
|
||||
selection target understood by Emacs.
|
||||
|
||||
@item MULTIPLE
|
||||
This selection converter is implemented in C code and is used to
|
||||
implement efficient transfer of selection requests which specify
|
||||
multiple selection targets at the same time.
|
||||
|
||||
@item LENGTH
|
||||
This selection converter returns the length of the selection data, in
|
||||
bytes.
|
||||
|
||||
@item DELETE
|
||||
This selection converter is used for internal purposes during
|
||||
drag-and-drop operations.
|
||||
|
||||
@item FILE_NAME
|
||||
This selection converter returns the file name of the buffer
|
||||
containing the selection data.
|
||||
|
||||
@item CHARACTER_POSITION
|
||||
This selection converter returns the character positions of each end
|
||||
of the selection in the buffer containing the selection data.
|
||||
|
||||
@item LINE_NUMBER
|
||||
@item COLUMN_NUMBER
|
||||
This selection converter returns the line and column numbers of each
|
||||
end of the selection in the buffer containing the selection data.
|
||||
|
||||
@item OWNER_OS
|
||||
This selection converter returns the name of the operating system on
|
||||
which Emacs is running.
|
||||
|
||||
@item HOST_NAME
|
||||
This selection converter returns the fully-qualified domain name of
|
||||
the machine on which Emacs is running.
|
||||
|
||||
@item USER
|
||||
This selection converter returns the username of the user account
|
||||
under which Emacs is running.
|
||||
|
||||
@item CLASS
|
||||
@item NAME
|
||||
These selection converters return the resource class and name used by
|
||||
Emacs.
|
||||
|
||||
@item INTEGER
|
||||
This selection converter returns an integer value verbatim.
|
||||
|
||||
@item SAVE_TARGETS
|
||||
@item _EMACS_INTERNAL
|
||||
These selection converters are used for internal purposes.
|
||||
@end table
|
||||
|
||||
With the exception of @code{INTEGER}, all selection converters
|
||||
expect the value given to @code{gui-set-selection} to be one of the
|
||||
following:
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
A string.
|
||||
|
||||
@item
|
||||
A list of the form @w{@code{(@var{beg} @var{end} @var{buf})}}, where
|
||||
@var{beg} and @var{end} are two markers or overlays describing the
|
||||
bounds of the selection data in the buffer @var{buf}.
|
||||
@end itemize
|
||||
|
||||
@node Other Selections
|
||||
@subsection Other Selections
|
||||
|
||||
Window systems such as MS-Windows, Nextstep, Haiku and Android do
|
||||
not provide selections corresponding to the X semantics. Each window
|
||||
system provides its own ad-hoc emulation of selections, none of which
|
||||
make use of the ``selection converter'' mechanism described above. In
|
||||
addition, only the @code{PRIMARY}, @code{CLIPBOARD}, and
|
||||
@code{SECONDARY} selections are typically supported, alongside the
|
||||
@code{XdndSelection} used for drag-and-drop operations.
|
||||
|
||||
GTK itself exposes emulations of X selections to applications, but
|
||||
those emulations are of varying completeness. While Emacs built with
|
||||
PGTK will use the same selection interface as Emacs built with X, many
|
||||
selection targets will not be useful.
|
||||
|
||||
On MS-Windows, @code{gui-get-selection} accepts a single target,
|
||||
@code{STRING}. The value returned is the selection data decoded
|
||||
using @code{selection-coding-system}.
|
||||
|
||||
@code{gui-set-selection} also only accepts strings, encodes them
|
||||
in the selection coding system, and saves them to the clipboard.
|
||||
|
||||
On Nextstep, Emacs only supports saving strings to selections.
|
||||
However, requests for the following targets are accepted:
|
||||
|
||||
@c FIXME: how is the text coding system determined, and do image/* or
|
||||
@c application/* return image data or file names?
|
||||
@itemize @bullet
|
||||
@item text/plain
|
||||
@item image/png
|
||||
@item text/html
|
||||
@item application/pdf
|
||||
@item application/rtf
|
||||
@item application/rtfd
|
||||
@item STRING
|
||||
@item text/plain
|
||||
@item image/tiff
|
||||
@end itemize
|
||||
|
||||
On Haiku, Emacs supports the same selection values as on X. In
|
||||
addition, Emacs fully implements the primary and secondary selections.
|
||||
However, instead of taking ownership over the selection data, Emacs
|
||||
transfers the selection data to the window server when
|
||||
@code{gui-set-selection} is called. The Haiku window server expects
|
||||
selection data to be provided in the form of a ``message'', containing
|
||||
associations between data types and selection data.
|
||||
|
||||
@defvar haiku-normal-selection-encoders
|
||||
List of functions which act as selection encoders. When
|
||||
@code{gui-set-selection} is called, each function in this list is
|
||||
successively called with its @var{selection} and @var{value}
|
||||
arguments. If the function returns non-@code{nil}, it should return a
|
||||
list of the form @w{@code{(@var{key} @var{type} @var{value})}}, where
|
||||
@var{key} is the name of the data type being transferred, @var{type}
|
||||
is either a number identifying a data type (in which case @var{value}
|
||||
should be a unibyte string that is directly transferred to the window
|
||||
server), or a symbol identifying both a data type and how @var{value}
|
||||
should be interpreted.
|
||||
@end defvar
|
||||
|
||||
Here are the meaningful values of @var{type}, and what they will
|
||||
cause Emacs to interpret @var{value} as:
|
||||
|
||||
@table @code
|
||||
@item string
|
||||
A unibyte string. The string is NULL-terminated after being placed in
|
||||
the message.
|
||||
|
||||
@item ref
|
||||
A file name. The file is looked up and file system information
|
||||
identifying the file is placed in the message.
|
||||
|
||||
@item short
|
||||
A 16-bit integer value.
|
||||
|
||||
@item long
|
||||
A 32-bit integer value.
|
||||
|
||||
@item llong
|
||||
A 64-bit integer value.
|
||||
|
||||
@item byte
|
||||
@item char
|
||||
An unsigned byte between 0 and 255.
|
||||
|
||||
@item size_t
|
||||
A number between 0 and 1 minus two to the power of the word size of
|
||||
the computer Emacs is running on.
|
||||
|
||||
@item ssize_t
|
||||
A number which fits in the C type @code{ssize_t}.
|
||||
|
||||
@item point
|
||||
A cons of two floats, specifying a coordinate on-screen.
|
||||
|
||||
@item float
|
||||
@item double
|
||||
A single or double-precision floating point number in an unspecified
|
||||
format.
|
||||
|
||||
@item (haiku-numeric-enum MIME)
|
||||
A unibyte string containing data in a certain MIME type.
|
||||
@end table
|
||||
|
||||
Under Haiku, @code{gui-get-selection} accepts either the targets
|
||||
@code{TARGETS} and @code{TIMESTAMP}, where the former returns a vector
|
||||
containing supported data types (much like on X), and the latter
|
||||
returns the number of times the selection has been set, the targets
|
||||
@code{STRING} and @code{UTF8_STRING}, which return text in ISO-Latin-1
|
||||
and UTF-8 format, or a MIME type, in which the data is returned
|
||||
undecoded as a unibyte string.
|
||||
|
||||
Under Android, @code{gui-get-selection} is restricted to returning
|
||||
UTF-8 string data of the type @code{STRING}, or image and application
|
||||
data associated with a MIME type. @code{gui-set-selection} will only
|
||||
set string data, as on MS-Windows.
|
||||
|
||||
@node Yanking Media
|
||||
@section Yanking Media
|
||||
|
||||
|
|
|
@ -2044,6 +2044,15 @@ to turn the character that follows into a Hyper character:
|
|||
@end group
|
||||
@end example
|
||||
|
||||
@cindex accessing events within a key translation function
|
||||
@vindex current-key-remap-sequence
|
||||
A key translation function might want to adjust its behavior based on
|
||||
parameters to events within a key sequence containing non-key events
|
||||
(@pxref{Input Events}.) This information is available from the
|
||||
variable @code{current-key-remap-sequence}, which is bound to the key
|
||||
sub-sequence being translated around calls to key translation
|
||||
functions.
|
||||
|
||||
@subsection Interaction with normal keymaps
|
||||
|
||||
The end of a key sequence is detected when that key sequence either is bound
|
||||
|
@ -2588,6 +2597,12 @@ function should return the binding to use instead.
|
|||
Emacs can call this function at any time that it does redisplay or
|
||||
operates on menu data structures, so you should write it so it can
|
||||
safely be called at any time.
|
||||
|
||||
@item :wrap @var{wrap-p}
|
||||
If @var{wrap-p} is non-nil inside a tool bar, the menu item is not
|
||||
displayed, but instead causes subsequent items to be displayed on a
|
||||
new line. This is not supported when Emacs uses the GTK+ or Nextstep
|
||||
toolkits.
|
||||
@end table
|
||||
|
||||
@node Menu Separators
|
||||
|
@ -3094,6 +3109,16 @@ specifies the local map to make the definition in. The argument
|
|||
@code{tool-bar-add-item-from-menu}.
|
||||
@end defun
|
||||
|
||||
@vindex secondary-tool-bar-map
|
||||
In addition to the tool bar items defined in @code{tool-bar-map},
|
||||
Emacs also supports displaying an additional row of ``secondary'' tool
|
||||
bar items specified in the keymap @code{secondary-tool-bar-map}.
|
||||
These items are normally displayed below those defined within
|
||||
@code{tool-bar-map} if the tool bar is positioned at the top of its
|
||||
frame, but are displayed above them if the tool bar is positioned at
|
||||
the bottom (@pxref{Layout Parameters}.) They are not displayed if the
|
||||
tool bar is positioned at the left or right of a frame.
|
||||
|
||||
@defvar auto-resize-tool-bars
|
||||
If this variable is non-@code{nil}, the tool bar automatically resizes to
|
||||
show all defined tool bar items---but not larger than a quarter of the
|
||||
|
|
|
@ -972,6 +972,9 @@ Hewlett-Packard HPUX operating system.
|
|||
@item nacl
|
||||
Google Native Client (@acronym{NaCl}) sandboxing system.
|
||||
|
||||
@item android
|
||||
The Open Handset Alliance's Android operating system.
|
||||
|
||||
@item ms-dos
|
||||
Microsoft's DOS@. Emacs compiled with DJGPP for MS-DOS binds
|
||||
@code{system-type} to @code{ms-dos} even when you run it on MS-Windows.
|
||||
|
|
|
@ -185,6 +185,24 @@ respective remote host. In case of a local @code{default-directory},
|
|||
the function returns just the value of the variable @code{exec-path}.
|
||||
@end defun
|
||||
|
||||
@cindex programs distributed with Emacs, starting
|
||||
@vindex ctags-program-name
|
||||
@vindex etags-program-name
|
||||
@vindex hexl-program-name
|
||||
@vindex emacsclient-program-name
|
||||
@vindex movemail-program-name
|
||||
@vindex ebrowse-program-manem
|
||||
When starting a program that is part of the Emacs distribution,
|
||||
you must take into account that the program may have been renamed in
|
||||
order to comply with executable naming restrictions present on the
|
||||
system.
|
||||
|
||||
Instead of starting @command{ctags}, for example, you should specify
|
||||
the value of @code{ctags-program-name} instead. Likewise, instead of
|
||||
starting @command{movemail}, you must start
|
||||
@code{movemail-program-name}, and the same goes for @command{etags},
|
||||
@command{hexl}, @command{emacsclient}, and @command{ebrowse}.
|
||||
|
||||
@node Shell Arguments
|
||||
@section Shell Arguments
|
||||
@cindex arguments for shell commands
|
||||
|
|
33
etc/DEBUG
33
etc/DEBUG
|
@ -1099,6 +1099,39 @@ Please refer to the LLDB reference on the web for more information
|
|||
about LLDB. If you already know GDB, you will also find a mapping
|
||||
from GDB commands to corresponding LLDB commands there.
|
||||
|
||||
** Debugging Emacs on Android.
|
||||
|
||||
Attaching GDB to Emacs running inside the Android application setup
|
||||
requires a special script found in the java/ directory, and a suitable
|
||||
GDB server binary to be present on the Android device, which is
|
||||
present on the free versions of Android. Connecting to the device
|
||||
also requires the `adb' (Android Debug Bridge) utility, and telling
|
||||
the Android system to resume the Emacs process after startup requires
|
||||
the Java debugger (jdb).
|
||||
|
||||
If all three of those tools are present, simply run (from the Emacs
|
||||
source directory):
|
||||
|
||||
../java/debug.sh -- [any extra arguments you wish to pass to gdb]
|
||||
|
||||
After which, upon waiting a while, the GDB prompt will show up.
|
||||
|
||||
If Emacs crashes and "JNI ERROR" shows up in the Android system log,
|
||||
then placing a breakpoint on:
|
||||
|
||||
break art::JavaVMExt::JniAbort
|
||||
|
||||
will let you find the source of the crash.
|
||||
|
||||
If there is no `gdbserver' binary present on the device, then you can
|
||||
specify one to upload, like so:
|
||||
|
||||
../java/debug.sh --gdbserver /path/to/gdbserver
|
||||
|
||||
In addition, when Emacs runs as a 64-bit process on a system
|
||||
supporting both 64 and 32-bit binaries, you must specify the path to a
|
||||
64-bit gdbserver binary.
|
||||
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
|
|
12
etc/MACHINES
12
etc/MACHINES
|
@ -131,6 +131,18 @@ the list at the end of this file.
|
|||
The earliest release of Haiku that will successfully compile Emacs
|
||||
is R1/Beta2. For windowing support, R1/Beta3 or later is required.
|
||||
|
||||
** Android
|
||||
|
||||
Emacs is known to run on all Android versions from 2.2 onwards, on
|
||||
Linux kernel 2.26.29 or later.
|
||||
|
||||
Android 2.2 has only been tested on ARM. mips64 has not been
|
||||
tested, but builds. With these exceptions, Emacs is known to run on
|
||||
all supported versions of Android on all supported machines: arm,
|
||||
armv7, arm64, x86, x86_64, and mips.
|
||||
|
||||
See the file java/INSTALL for detailed installation instructions.
|
||||
|
||||
|
||||
* Obsolete platforms
|
||||
|
||||
|
|
58
etc/NEWS
58
etc/NEWS
|
@ -24,6 +24,12 @@ applies, and please also update docstrings as needed.
|
|||
|
||||
* Installation Changes in Emacs 30.1
|
||||
|
||||
** Emacs has been ported to the Android operating system.
|
||||
This requires Emacs to be compiled on another computer. The Android
|
||||
NDK, SDK, and a suitable Java compiler must also be installed.
|
||||
|
||||
See the file 'java/INSTALL' for more details.
|
||||
|
||||
---
|
||||
** Emacs now defaults to ossaudio library for sound on NetBSD and OpenBSD.
|
||||
Previously configure used ALSA libraries if installed on the
|
||||
|
@ -62,6 +68,12 @@ compositing manager, Emacs will now redisplay such a frame even though
|
|||
'frame-visible-p' returns nil or 'icon' for it. This can happen, for
|
||||
example, as part of preview for iconified frames.
|
||||
|
||||
---
|
||||
** New user option 'menu-bar-close-window'.
|
||||
When non-nil, selecting Close from the File menu or clicking Close in
|
||||
the tool bar will result in the current window being closed, if
|
||||
possible.
|
||||
|
||||
+++
|
||||
** 'write-region-inhibit-fsync' now defaults to t in interactive mode,
|
||||
as it has in batch mode since Emacs 24.
|
||||
|
@ -102,6 +114,11 @@ plus, minus, check-mark, start, etc.
|
|||
The 'tool-bar-position' frame parameter can be set to 'bottom' on all
|
||||
window systems other than Nextstep.
|
||||
|
||||
+++
|
||||
** New global minor mode 'modifier-bar-mode'.
|
||||
When this minor mode is enabled, buttons representing modifier keys
|
||||
are displayed along the tool bar.
|
||||
|
||||
---
|
||||
** New user option 'uniquify-dirname-transform'.
|
||||
This can be used to customize how buffer names are uniquified, by
|
||||
|
@ -128,6 +145,13 @@ right-aligned to is controlled by the new user option
|
|||
|
||||
* Editing Changes in Emacs 30.1
|
||||
|
||||
+++
|
||||
** Emacs now has better support for touchscreen devices.
|
||||
Many touch screen gestures are now implemented and translated into
|
||||
mouse or gesture events, and support for tapping tool bar buttons and
|
||||
opening menus has been written. Countless packages, such as Dired and
|
||||
Custom have been adjusted to better understand touch screen input.
|
||||
|
||||
---
|
||||
** On X, Emacs now supports input methods which perform "string conversion".
|
||||
This means an input method can now ask Emacs to delete text
|
||||
|
@ -417,6 +441,12 @@ this new face when DocView displays documents, customize this face to
|
|||
restore the colors you were used to, or to get colors more to your
|
||||
liking.
|
||||
|
||||
---
|
||||
*** DocView buffers now display a new tool bar.
|
||||
This tool bar contains options for searching and navigating within the
|
||||
document, replacing the incompatible items for incremental search and
|
||||
editing within the default tool bar displayed in the past.
|
||||
|
||||
** Shortdoc
|
||||
|
||||
+++
|
||||
|
@ -714,6 +744,29 @@ See (info "(elisp)Porting Old Advice") for help converting them
|
|||
to use `advice-add` or `define-advice instead.
|
||||
|
||||
+++
|
||||
** New variable 'current-key-remap-sequence'.
|
||||
It is bound to the key sequence that caused a call to a function bound
|
||||
within `function-key-map' or `input-decode-map' around those calls.
|
||||
|
||||
+++
|
||||
** New variables describing the names of built in programs.
|
||||
The new variables 'ctags-program-name', 'ebrowse-program-name',
|
||||
'etags-program-name', 'hexl-program-name', 'emacsclient-program-name'
|
||||
and 'movemail-program-name' should be used instead of "ctags",
|
||||
"ebrowse", "etags", "hexl", and "emacsclient", when starting one of
|
||||
these built in programs in a subprocess.
|
||||
|
||||
+++
|
||||
** 'x-popup-menu' now understands touch screen events.
|
||||
When a 'touchscreen-begin' or 'touchscreen-end' event is passed as the
|
||||
POSITION argument, it will behave as if that event was a mouse event.
|
||||
|
||||
+++
|
||||
** New functions for handling touch screen events.
|
||||
The new functions 'touch-screen-track-tap' and
|
||||
'touch-screen-track-drag' handle tracking common touch screen gestures
|
||||
from within a command.
|
||||
|
||||
** New user option 'safe-local-variable-directories'.
|
||||
This user option names directories in which Emacs will treat all
|
||||
directory-local variables as safe.
|
||||
|
@ -726,6 +779,11 @@ with Emacs.
|
|||
|
||||
** New variable 'inhibit-auto-fill' to temporarily prevent auto-fill.
|
||||
|
||||
+++
|
||||
** New variable 'secondary-tool-bar-map'.
|
||||
If non-nil, this variable contains a keymap of menu items that are
|
||||
displayed along tool bar items inside 'tool-bar-map'.
|
||||
|
||||
** Functions and variables to transpose sexps
|
||||
|
||||
+++
|
||||
|
|
50
etc/PROBLEMS
50
etc/PROBLEMS
|
@ -3361,6 +3361,56 @@ Compose key to stop working.
|
|||
On X Windows, users should not use Emacs configured with PGTK, since
|
||||
this and many other problems do not exist on the regular X builds.
|
||||
|
||||
* Runtime problems specific to Android
|
||||
|
||||
** Text displayed in the default monospace font looks horrible.
|
||||
|
||||
Droid Sans Mono (the default Monospace font which comes with Android)
|
||||
comes with instruction code designed for Microsoft's proprietary
|
||||
TrueType font scaler. When this code is executed by Emacs to instruct
|
||||
a glyph containing more than one component, it tries to address
|
||||
"reference points" which are set to the values of two extra "phantom
|
||||
points" in the glyph, that are a proprietary extension of the MS font
|
||||
scaler.
|
||||
|
||||
Emacs does not support these extensions, and as a result characters
|
||||
such as
|
||||
|
||||
ĥ
|
||||
|
||||
display incorrectly, with the right most edge of the `h' component
|
||||
stretched very far out to the right, on some low density displays.
|
||||
|
||||
The solution is to replace the MS-specific hinting code in Droid Sans
|
||||
Mono with automatically generated code from the FreeType project's
|
||||
"ttfautohint" program. First, extract
|
||||
'/system/fonts/DroidSansMono.ttf' from your device:
|
||||
|
||||
$ adb pull /system/fonts/DroidSansMono.ttf
|
||||
/system/fonts/DroidSansMono.ttf: 1 file pulled, 0 skipped.
|
||||
23.1 MB/s (90208 bytes in 0.004s)
|
||||
|
||||
install the "ttfautohint" program:
|
||||
|
||||
http://freetype.org/ttfautohint/
|
||||
|
||||
generate a font file with new hinting instructions:
|
||||
|
||||
$ ttfautohint DroidSansMono.ttf > DroidSansMono.ttf.rpl
|
||||
|
||||
and upload them to your device, either back to /system/fonts (which is
|
||||
allowed by free versions of Android, such as Replicant):
|
||||
|
||||
$ adb root
|
||||
$ adb remount
|
||||
$ adb push DroidSansMono.ttf.rpl /system/fonts/DroidSansMono.ttf
|
||||
|
||||
or to the user fonts directory described in the "Android Fonts" node
|
||||
of the Emacs manual. You may want to perform this procedure even if
|
||||
you are not seeing problems with character display, as the
|
||||
automatically generated instructions result in superior display
|
||||
results that are easier to read.
|
||||
|
||||
* Build-time problems
|
||||
|
||||
** Configuration
|
||||
|
|
BIN
etc/images/alt.pbm
Normal file
BIN
etc/images/alt.pbm
Normal file
Binary file not shown.
BIN
etc/images/ctrl.pbm
Normal file
BIN
etc/images/ctrl.pbm
Normal file
Binary file not shown.
BIN
etc/images/hyper.pbm
Normal file
BIN
etc/images/hyper.pbm
Normal file
Binary file not shown.
BIN
etc/images/last-page.pbm
Normal file
BIN
etc/images/last-page.pbm
Normal file
Binary file not shown.
122
etc/images/last-page.xpm
Normal file
122
etc/images/last-page.xpm
Normal file
|
@ -0,0 +1,122 @@
|
|||
/* XPM */
|
||||
static char *last_page[] = {
|
||||
/* columns rows colors chars-per-pixel */
|
||||
"24 24 92 1 ",
|
||||
" c None",
|
||||
". c black",
|
||||
"X c gray15",
|
||||
"o c #2F4050",
|
||||
"O c #344353",
|
||||
"+ c #3B4F63",
|
||||
"@ c #384F66",
|
||||
"# c #3A5067",
|
||||
"$ c #3C5064",
|
||||
"% c #3C5065",
|
||||
"& c #3E5166",
|
||||
"* c #3F5266",
|
||||
"= c #3A5168",
|
||||
"- c #3B5269",
|
||||
"; c #3D526A",
|
||||
": c #3E546A",
|
||||
"> c #3F556B",
|
||||
", c #3E5975",
|
||||
"< c #3F5A76",
|
||||
"1 c #464646",
|
||||
"2 c #494949",
|
||||
"3 c #405367",
|
||||
"4 c #405468",
|
||||
"5 c #40566C",
|
||||
"6 c #41576D",
|
||||
"7 c #42586E",
|
||||
"8 c #44586F",
|
||||
"9 c #45596F",
|
||||
"0 c #465B70",
|
||||
"q c #415B77",
|
||||
"w c #425C78",
|
||||
"e c #435E79",
|
||||
"r c #445F7A",
|
||||
"t c #46607B",
|
||||
"y c #47617B",
|
||||
"u c #47617C",
|
||||
"i c #48627D",
|
||||
"p c #49637D",
|
||||
"a c #4B647E",
|
||||
"s c #4C647F",
|
||||
"d c #4C657F",
|
||||
"f c gray38",
|
||||
"g c #6A6A6A",
|
||||
"h c #616A73",
|
||||
"j c #68727D",
|
||||
"k c #7C7C7C",
|
||||
"l c #4E6780",
|
||||
"z c #4F6881",
|
||||
"x c #506982",
|
||||
"c c #526A83",
|
||||
"v c #556D85",
|
||||
"b c #5B7289",
|
||||
"n c #7D8185",
|
||||
"m c #77838F",
|
||||
"M c #868788",
|
||||
"N c #888888",
|
||||
"B c #8B8B8B",
|
||||
"V c #8F9296",
|
||||
"C c #8F9396",
|
||||
"Z c #8F9397",
|
||||
"A c #909397",
|
||||
"S c #959595",
|
||||
"D c #91969C",
|
||||
"F c #91979C",
|
||||
"G c #92979C",
|
||||
"H c #92979D",
|
||||
"J c #9C9FA1",
|
||||
"K c #9D9FA2",
|
||||
"L c #A2A3A4",
|
||||
"P c #A6A6A6",
|
||||
"I c #ACACAC",
|
||||
"U c gray68",
|
||||
"Y c #B0B0B0",
|
||||
"T c #B2B2B2",
|
||||
"R c gray71",
|
||||
"E c #B6B6B6",
|
||||
"W c gray75",
|
||||
"Q c #C5C5C5",
|
||||
"! c gray79",
|
||||
"~ c gray80",
|
||||
"^ c LightGray",
|
||||
"/ c #D6D6D6",
|
||||
"( c #D8D8D8",
|
||||
") c #DADADA",
|
||||
"_ c #DEDEDE",
|
||||
"` c gray89",
|
||||
"' c #E5E5E5",
|
||||
"] c #E6E6E6",
|
||||
"[ c #EEEEEE",
|
||||
"{ c #F2F2F2",
|
||||
"} c #F6F6F6",
|
||||
"| c white",
|
||||
/* pixels */
|
||||
" ",
|
||||
" ",
|
||||
" ........ ........ ",
|
||||
" .vU/_][`!N2gNT~)]{|b. ",
|
||||
" .@T/_][}||PUTW~)]{|t. ",
|
||||
" .#T/_][}`|PUTW~)]{|t. ",
|
||||
" .-T/_][).|PUTW~)]{|t. ",
|
||||
" .-T/_]^..|PUTW~)]{|t. ",
|
||||
" .;T/_~...|PUTW~)]{|u. ",
|
||||
" .>T/Q.....X1fkSR]{|i. ",
|
||||
" .>T/_~...|PUTW~)]{|i. ",
|
||||
" .5T/_]^..|PUTW~)]{|a. ",
|
||||
" .5T/_][).|PUTW~)]{|d. ",
|
||||
" .7T/_][}`|PUTW~)]{|d. ",
|
||||
" .8T/_][}||PUTW~)]{|l. ",
|
||||
" .8R/_][}||PUTW~)]{|z. ",
|
||||
" .0MAZZZZZKPLHHHHHKmc. ",
|
||||
" .O43&&&&+hnjtrwwq<<c. ",
|
||||
" ..........o......... ",
|
||||
" ... ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" "
|
||||
};
|
BIN
etc/images/meta.pbm
Normal file
BIN
etc/images/meta.pbm
Normal file
Binary file not shown.
BIN
etc/images/shift.pbm
Normal file
BIN
etc/images/shift.pbm
Normal file
Binary file not shown.
BIN
etc/images/super.pbm
Normal file
BIN
etc/images/super.pbm
Normal file
Binary file not shown.
140
exec/Makefile.in
Normal file
140
exec/Makefile.in
Normal file
|
@ -0,0 +1,140 @@
|
|||
### @configure_input@
|
||||
|
||||
# Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU Emacs.
|
||||
|
||||
# GNU Emacs is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# GNU Emacs is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# Configure build directory information.
|
||||
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
builddir = @builddir@
|
||||
|
||||
# Set up compilation tools.
|
||||
|
||||
CC = @CC@
|
||||
AS = @AS@
|
||||
LD = @LD@
|
||||
M4 = @M4@
|
||||
CPP = @CPP@
|
||||
ASFLAGS = @ASFLAGS@
|
||||
ARFLAGS = @ARFLAGS@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LOADERFLAGS = @LOADERFLAGS@
|
||||
FIND_DELETE = @FIND_DELETE@
|
||||
|
||||
# Set up object files.
|
||||
|
||||
LOADER = @exec_loader@
|
||||
OBJS = @OBJS@
|
||||
LOADOBJS = $(patsubst %.s,%.o,$(LOADER))
|
||||
|
||||
# Set up automatic dependency tracking.
|
||||
|
||||
AUTO_DEPEND = @AUTO_DEPEND@
|
||||
DEPDIR = deps
|
||||
ifeq ($(AUTO_DEPEND),yes)
|
||||
DEPFLAGS = -MMD -MF $(DEPDIR)/$*.d -MP
|
||||
-include $(OBJS:%.o=$(DEPDIR)/%.d)
|
||||
-include $(DEPDIR)/test.d
|
||||
-include $(DEPDIR)/exec1.d
|
||||
else
|
||||
DEPFLAGS =
|
||||
include $(srcdir)/deps.mk
|
||||
endif
|
||||
|
||||
# Set up the appropriate targets.
|
||||
|
||||
all: libexec.a loader
|
||||
|
||||
# Set up automatic Makefile regeneration.
|
||||
|
||||
$(srcdir)/configure: $(srcdir)/configure.ac
|
||||
cd $(srcdir) && autoreconf
|
||||
|
||||
config.status: $(srcdir)/configure
|
||||
if [ -x config.status ]; then \
|
||||
./config.status --recheck; \
|
||||
else \
|
||||
$(srcdir)/configure; \
|
||||
fi
|
||||
|
||||
Makefile: config.status Makefile.in
|
||||
MAKE="$(MAKE)" ./config.status
|
||||
|
||||
# Set up rules to build targets.
|
||||
|
||||
.SUFFIXES: .c .s
|
||||
.c.o:
|
||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEPFLAGS) -I. -I$(srcdir) $< -o $@
|
||||
.s.o:
|
||||
$(M4) $< > $(notdir $<).s
|
||||
$(AS) $(ASFLAGS) $(notdir $<).s -o $@
|
||||
|
||||
# Set up dependencies for config-mips.m4.
|
||||
|
||||
config-mips.m4: config-mips.m4.in
|
||||
cd $(srcdir) && ./config.status $@
|
||||
$(LOADOBJS): config-mips.m4
|
||||
|
||||
# Set up rules to build libexec.a.
|
||||
|
||||
libexec.a: $(OBJS)
|
||||
$(AR) cru $(ARFLAGS) $@ $^
|
||||
|
||||
# And loader.
|
||||
|
||||
loader: $(LOADOBJS)
|
||||
$(LD) -o $@ $(LOADERFLAGS) $(LOADOBJS)
|
||||
|
||||
# And test.
|
||||
|
||||
test: test.o libexec.a
|
||||
$(CC) $(LDFLAGS) $< libexec.a -o $@
|
||||
|
||||
# And exec1.
|
||||
|
||||
exec1: exec1.o libexec.a
|
||||
$(CC) $(LDFLAGS) $< libexec.a -o $@
|
||||
|
||||
# Set up targets for cleaning.
|
||||
|
||||
.PHONY: clean distclean maintainer-clean extraclean bootstrap-clean
|
||||
clean:
|
||||
rm -f *.o *.a loader test exec1 *.s.s
|
||||
ifeq ($(AUTO_DEPEND),yes)
|
||||
rm -rf deps/*.d
|
||||
endif
|
||||
|
||||
distclean: clean
|
||||
rm -f Makefile config.status config.h config-mips.m4
|
||||
|
||||
maintainer-clean: distclean
|
||||
|
||||
### This doesn't actually appear in the coding standards, but Karl
|
||||
### says GCC supports it, and that's where the configuration part of
|
||||
### the coding standards seem to come from. It's like distclean, but
|
||||
### it deletes backup and autosave files too.
|
||||
|
||||
extraclean: maintainer-clean
|
||||
-rm -f config-tmp-* $(srcdir)/aclocal.m4 $(srcdir)/configure \
|
||||
$(srcdir)/src/config.in
|
||||
-[ "$(srcdir)" = "." ] || \
|
||||
find $(srcdir) '(' -name '*~' -o -name '#*' ')' $(FIND_DELETE)
|
||||
-find . '(' -name '*~' -o -name '#*' ')' $(FIND_DELETE)
|
||||
bootstrap-clean: extraclean
|
3
exec/README
Normal file
3
exec/README
Normal file
|
@ -0,0 +1,3 @@
|
|||
This directory holds the source code to a library used to replace the
|
||||
`execve' and `execveat' system calls, used by the Android port of
|
||||
Emacs to start executables without intervention from the system.
|
42
exec/config-mips.m4.in
Normal file
42
exec/config-mips.m4.in
Normal file
|
@ -0,0 +1,42 @@
|
|||
dnl Assembler templates for MIPS computers.
|
||||
dnl
|
||||
dnl Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
dnl
|
||||
dnl This file is part of GNU Emacs.
|
||||
dnl
|
||||
dnl GNU Emacs is free software: you can redistribute it and/or modify
|
||||
dnl it under the terms of the GNU General Public License as published by
|
||||
dnl the Free Software Foundation, either version 3 of the License, or
|
||||
dnl (at your option) any later version.
|
||||
dnl
|
||||
dnl GNU Emacs is distributed in the hope that it will be useful,
|
||||
dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
dnl GNU General Public License for more details.
|
||||
dnl
|
||||
dnl You should have received a copy of the GNU General Public License
|
||||
dnl along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
define(`SYSCALL_open', `ifelse(`@MIPS_N32@',`yes',`6002',`4005')')
|
||||
define(`SYSCALL_close', `ifelse(`@MIPS_N32@',`yes',`6003',`4006')')
|
||||
define(`SYSCALL_mmap', `ifelse(`@MIPS_N32@',`yes',`6009',`4090')')
|
||||
define(`SYSCALL_nanosleep', `ifelse(`@MIPS_N32@',`yes',`6034',`4166')')
|
||||
define(`SYSCALL_exit', `ifelse(`@MIPS_N32@',`yes',`6058',`4001')')
|
||||
define(`SYSCALL_prctl', `ifelse(`@MIPS_N32@',`yes',`6153',`4192')')
|
||||
|
||||
define(`SYSCALL', `ifelse(`@MIPS_N32@',`yes',` move $a4, $1
|
||||
move $a5, $2
|
||||
move $a6, $3
|
||||
move $a7, $4',` addi $sp, -32
|
||||
sw $1, 16($sp)
|
||||
sw $2, 20($sp)
|
||||
sw $3, 24($sp)
|
||||
sw $4, 28($sp)')')
|
||||
|
||||
define(`RESTORE', `ifelse(`@MIPS_N32@',`yes',` nop',` addi $sp, 32')')
|
||||
|
||||
dnl For mips64. Some assemblers don't want to assemble `daddi'.
|
||||
define(`DADDI2', `ifelse(`@DADDI_BROKEN@',`yes',` li $at, $2
|
||||
dadd $1, $1, $at',` daddi $1, $2')')
|
||||
define(`DADDI3', `ifelse(`@DADDI_BROKEN@',`yes',` li $at, $3
|
||||
dadd $1, $2, $at',` daddi $1, $2, $3')')
|
1768
exec/config.guess
vendored
Executable file
1768
exec/config.guess
vendored
Executable file
File diff suppressed because it is too large
Load diff
358
exec/config.h.in
Normal file
358
exec/config.h.in
Normal file
|
@ -0,0 +1,358 @@
|
|||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation, either version 3 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Define to number of reserved bytes past the stack frame. */
|
||||
#undef ABI_RED_ZONE
|
||||
|
||||
/* Define if building universal (internal helper macro) */
|
||||
#undef AC_APPLE_UNIVERSAL_BUILD
|
||||
|
||||
/* Define to number of the `clone3' system call. */
|
||||
#undef CLONE3_SYSCALL
|
||||
|
||||
/* Define to number of the `clone' system call. */
|
||||
#undef CLONE_SYSCALL
|
||||
|
||||
/* Virtual address for loading PIC executables */
|
||||
#undef EXECUTABLE_BASE
|
||||
|
||||
/* Define to 1 if the system utilizes 64-bit ELF. */
|
||||
#undef EXEC_64
|
||||
|
||||
/* Define to number of the `exec' system call. */
|
||||
#undef EXEC_SYSCALL
|
||||
|
||||
/* Define to 1 if you have the declaration of `stpcpy', and to 0 if you don't.
|
||||
*/
|
||||
#undef HAVE_DECL_STPCPY
|
||||
|
||||
/* Define to 1 if you have the declaration of `stpncpy', and to 0 if you
|
||||
don't. */
|
||||
#undef HAVE_DECL_STPNCPY
|
||||
|
||||
/* Define to 1 if you have the `getpagesize' function. */
|
||||
#undef HAVE_GETPAGESIZE
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the <minix/config.h> header file. */
|
||||
#undef HAVE_MINIX_CONFIG_H
|
||||
|
||||
/* Define to 1 if process_vm_readv is available. */
|
||||
#undef HAVE_PROCESS_VM
|
||||
|
||||
/* Define to 1 if `si_syscall' is a member of `siginfo_t'. */
|
||||
#undef HAVE_SIGINFO_T_SI_SYSCALL
|
||||
|
||||
/* Define to 1 if stdbool.h conforms to C99. */
|
||||
#undef HAVE_STDBOOL_H
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdio.h> header file. */
|
||||
#undef HAVE_STDIO_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the `stpcpy' function. */
|
||||
#undef HAVE_STPCPY
|
||||
|
||||
/* Define to 1 if you have the `stpncpy' function. */
|
||||
#undef HAVE_STPNCPY
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <sys/param.h> header file. */
|
||||
#undef HAVE_SYS_PARAM_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <sys/uio.h> header file. */
|
||||
#undef HAVE_SYS_UIO_H
|
||||
|
||||
/* Define to 1 if the system has the type `uintptr_t'. */
|
||||
#undef HAVE_UINTPTR_T
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to 1 if you have the <wchar.h> header file. */
|
||||
#undef HAVE_WCHAR_H
|
||||
|
||||
/* Define to 1 if the system has the type `_Bool'. */
|
||||
#undef HAVE__BOOL
|
||||
|
||||
/* Virtual address for loading PIC interpreters */
|
||||
#undef INTERPRETER_BASE
|
||||
|
||||
/* Define to 1 if MIPS NABI calling convention is being used. */
|
||||
#undef MIPS_NABI
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define to number of the `readlinkat' system call. */
|
||||
#undef READLINKAT_SYSCALL
|
||||
|
||||
/* Define to number of the `readlink' system call. */
|
||||
#undef READLINK_SYSCALL
|
||||
|
||||
/* Define to 1 if the library is used within a signal handler. */
|
||||
#undef REENTRANT
|
||||
|
||||
/* Define to 1 if the stack grows downwards. */
|
||||
#undef STACK_GROWS_DOWNWARDS
|
||||
|
||||
/* Define to register holding the stack pointer. */
|
||||
#undef STACK_POINTER
|
||||
|
||||
/* Define to 1 if all of the C90 standard headers exist (not just the ones
|
||||
required in a freestanding environment). This macro is provided for
|
||||
backward compatibility; new code need not use it. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Define to register holding arg1 to system calls. */
|
||||
#undef SYSCALL_ARG1_REG
|
||||
|
||||
/* Define to register holding arg2 to system calls. */
|
||||
#undef SYSCALL_ARG2_REG
|
||||
|
||||
/* Define to register holding arg3 to system calls. */
|
||||
#undef SYSCALL_ARG3_REG
|
||||
|
||||
/* Define to register holding arg0 to system calls. */
|
||||
#undef SYSCALL_ARG_REG
|
||||
|
||||
/* Define to header holding system call numbers. */
|
||||
#undef SYSCALL_HEADER
|
||||
|
||||
/* Define to register holding the system call number. */
|
||||
#undef SYSCALL_NUM_REG
|
||||
|
||||
/* Define to register holding value of system calls. */
|
||||
#undef SYSCALL_RET_REG
|
||||
|
||||
/* Define to header holding USER_REGS_STRUCT. */
|
||||
#undef USER_HEADER
|
||||
|
||||
/* Define to structure holding user registers. */
|
||||
#undef USER_REGS_STRUCT
|
||||
|
||||
/* Define to word type used by tracees. */
|
||||
#undef USER_WORD
|
||||
|
||||
/* Enable extensions on AIX 3, Interix. */
|
||||
#ifndef _ALL_SOURCE
|
||||
# undef _ALL_SOURCE
|
||||
#endif
|
||||
/* Enable general extensions on macOS. */
|
||||
#ifndef _DARWIN_C_SOURCE
|
||||
# undef _DARWIN_C_SOURCE
|
||||
#endif
|
||||
/* Enable general extensions on Solaris. */
|
||||
#ifndef __EXTENSIONS__
|
||||
# undef __EXTENSIONS__
|
||||
#endif
|
||||
/* Enable GNU extensions on systems that have them. */
|
||||
#ifndef _GNU_SOURCE
|
||||
# undef _GNU_SOURCE
|
||||
#endif
|
||||
/* Enable X/Open compliant socket functions that do not require linking
|
||||
with -lxnet on HP-UX 11.11. */
|
||||
#ifndef _HPUX_ALT_XOPEN_SOCKET_API
|
||||
# undef _HPUX_ALT_XOPEN_SOCKET_API
|
||||
#endif
|
||||
/* Identify the host operating system as Minix.
|
||||
This macro does not affect the system headers' behavior.
|
||||
A future release of Autoconf may stop defining this macro. */
|
||||
#ifndef _MINIX
|
||||
# undef _MINIX
|
||||
#endif
|
||||
/* Enable general extensions on NetBSD.
|
||||
Enable NetBSD compatibility extensions on Minix. */
|
||||
#ifndef _NETBSD_SOURCE
|
||||
# undef _NETBSD_SOURCE
|
||||
#endif
|
||||
/* Enable OpenBSD compatibility extensions on NetBSD.
|
||||
Oddly enough, this does nothing on OpenBSD. */
|
||||
#ifndef _OPENBSD_SOURCE
|
||||
# undef _OPENBSD_SOURCE
|
||||
#endif
|
||||
/* Define to 1 if needed for POSIX-compatible behavior. */
|
||||
#ifndef _POSIX_SOURCE
|
||||
# undef _POSIX_SOURCE
|
||||
#endif
|
||||
/* Define to 2 if needed for POSIX-compatible behavior. */
|
||||
#ifndef _POSIX_1_SOURCE
|
||||
# undef _POSIX_1_SOURCE
|
||||
#endif
|
||||
/* Enable POSIX-compatible threading on Solaris. */
|
||||
#ifndef _POSIX_PTHREAD_SEMANTICS
|
||||
# undef _POSIX_PTHREAD_SEMANTICS
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */
|
||||
#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__
|
||||
# undef __STDC_WANT_IEC_60559_ATTRIBS_EXT__
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */
|
||||
#ifndef __STDC_WANT_IEC_60559_BFP_EXT__
|
||||
# undef __STDC_WANT_IEC_60559_BFP_EXT__
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */
|
||||
#ifndef __STDC_WANT_IEC_60559_DFP_EXT__
|
||||
# undef __STDC_WANT_IEC_60559_DFP_EXT__
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */
|
||||
#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__
|
||||
# undef __STDC_WANT_IEC_60559_FUNCS_EXT__
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC TS 18661-3:2015. */
|
||||
#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
|
||||
# undef __STDC_WANT_IEC_60559_TYPES_EXT__
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */
|
||||
#ifndef __STDC_WANT_LIB_EXT2__
|
||||
# undef __STDC_WANT_LIB_EXT2__
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC 24747:2009. */
|
||||
#ifndef __STDC_WANT_MATH_SPEC_FUNCS__
|
||||
# undef __STDC_WANT_MATH_SPEC_FUNCS__
|
||||
#endif
|
||||
/* Enable extensions on HP NonStop. */
|
||||
#ifndef _TANDEM_SOURCE
|
||||
# undef _TANDEM_SOURCE
|
||||
#endif
|
||||
/* Enable X/Open extensions. Define to 500 only if necessary
|
||||
to make mbstate_t available. */
|
||||
#ifndef _XOPEN_SOURCE
|
||||
# undef _XOPEN_SOURCE
|
||||
#endif
|
||||
|
||||
|
||||
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
||||
significant byte first (like Motorola and SPARC, unlike Intel). */
|
||||
#if defined AC_APPLE_UNIVERSAL_BUILD
|
||||
# if defined __BIG_ENDIAN__
|
||||
# define WORDS_BIGENDIAN 1
|
||||
# endif
|
||||
#else
|
||||
# ifndef WORDS_BIGENDIAN
|
||||
# undef WORDS_BIGENDIAN
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
|
||||
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
|
||||
#define below would cause a syntax error. */
|
||||
#undef _UINT32_T
|
||||
|
||||
/* Define for Solaris 2.5.1 so the uint64_t typedef from <sys/synch.h>,
|
||||
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
|
||||
#define below would cause a syntax error. */
|
||||
#undef _UINT64_T
|
||||
|
||||
/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,
|
||||
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
|
||||
#define below would cause a syntax error. */
|
||||
#undef _UINT8_T
|
||||
|
||||
/* Define as a signed integer type capable of holding a process identifier. */
|
||||
#undef pid_t
|
||||
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
#undef size_t
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
#undef ssize_t
|
||||
|
||||
/* Define to the type of an unsigned integer type of width exactly 16 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
#undef uint16_t
|
||||
|
||||
/* Define to the type of an unsigned integer type of width exactly 32 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
#undef uint32_t
|
||||
|
||||
/* Define to the type of an unsigned integer type of width exactly 64 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
#undef uint64_t
|
||||
|
||||
/* Define to the type of an unsigned integer type of width exactly 8 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
#undef uint8_t
|
||||
|
||||
/* Define to the type of an unsigned integer type wide enough to hold a
|
||||
pointer, if such a type exists, and if the system does not define it. */
|
||||
#undef uintptr_t
|
||||
|
||||
|
||||
#ifdef HAVE_STDBOOL_H
|
||||
# include <stdbool.h>
|
||||
#else
|
||||
# ifndef HAVE__BOOL
|
||||
# ifdef __cplusplus
|
||||
typedef bool _Bool;
|
||||
# else
|
||||
# define _Bool signed char
|
||||
# endif
|
||||
# endif
|
||||
# define bool _Bool
|
||||
# define false 0
|
||||
# define true 1
|
||||
# define __bool_true_false_are_defined 1
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif /* HAVE_SYS_PARAM_H */
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#endif /* MAX */
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#endif /* MIN */
|
||||
|
1890
exec/config.sub
vendored
Executable file
1890
exec/config.sub
vendored
Executable file
File diff suppressed because it is too large
Load diff
537
exec/configure.ac
Normal file
537
exec/configure.ac
Normal file
|
@ -0,0 +1,537 @@
|
|||
dnl Autoconf script for GNU Emacs's exec library.
|
||||
dnl To rebuild the 'configure' script from this, execute the command
|
||||
dnl autoconf
|
||||
dnl in the directory containing this script.
|
||||
dnl If you changed any AC_DEFINES, also run autoheader.
|
||||
dnl
|
||||
dnl Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
dnl
|
||||
dnl This file is part of GNU Emacs.
|
||||
dnl
|
||||
dnl GNU Emacs is free software: you can redistribute it and/or modify
|
||||
dnl it under the terms of the GNU General Public License as published by
|
||||
dnl the Free Software Foundation, either version 3 of the License, or
|
||||
dnl (at your option) any later version.
|
||||
dnl
|
||||
dnl GNU Emacs is distributed in the hope that it will be useful,
|
||||
dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
dnl GNU General Public License for more details.
|
||||
dnl
|
||||
dnl You should have received a copy of the GNU General Public License
|
||||
dnl along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
AC_PREREQ([2.65])
|
||||
AC_INIT([libexec], [30.0.50], [bug-gnu-emacs@gnu.org], [],
|
||||
[https://www.gnu.org/software/emacs/])
|
||||
|
||||
AH_TOP([/* Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation, either version 3 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */])
|
||||
|
||||
AC_ARG_WITH([reentrancy],
|
||||
[AS_HELP_STRING([--with-reentrancy],
|
||||
[Generate library which can be used within a signal handler.])],
|
||||
[AC_DEFINE([REENTRANT], [1])])
|
||||
|
||||
AC_USE_SYSTEM_EXTENSIONS
|
||||
AC_PROG_CC
|
||||
AC_PROG_CPP
|
||||
AC_PROG_INSTALL
|
||||
|
||||
AC_TYPE_UINT8_T
|
||||
AC_TYPE_UINT16_T
|
||||
AC_TYPE_UINT32_T
|
||||
AC_TYPE_UINT64_T
|
||||
AC_TYPE_UINTPTR_T
|
||||
AC_TYPE_SIZE_T
|
||||
AC_TYPE_SSIZE_T
|
||||
AC_TYPE_PID_T
|
||||
|
||||
AC_HEADER_STDBOOL
|
||||
AC_CHECK_FUNCS([getpagesize stpcpy stpncpy])
|
||||
AC_CHECK_DECLS([stpcpy, stpncpy])
|
||||
AC_CHECK_FUNC([process_vm_readv],
|
||||
[AC_CHECK_FUNC([process_vm_writev],
|
||||
[AC_CHECK_DECL([process_vm_readv],
|
||||
[AC_DEFINE([HAVE_PROCESS_VM], [1],
|
||||
[Define to 1 if process_vm_readv is available.])],
|
||||
[], [[
|
||||
#include <sys/uio.h>
|
||||
]])])])
|
||||
AC_CHECK_HEADERS([sys/param.h sys/uio.h])
|
||||
AC_CHECK_MEMBERS([siginfo_t.si_syscall], [], [],
|
||||
[[
|
||||
#include <signal.h>
|
||||
]])
|
||||
|
||||
AH_BOTTOM([
|
||||
#ifdef HAVE_STDBOOL_H
|
||||
# include <stdbool.h>
|
||||
#else
|
||||
# ifndef HAVE__BOOL
|
||||
# ifdef __cplusplus
|
||||
typedef bool _Bool;
|
||||
# else
|
||||
# define _Bool signed char
|
||||
# endif
|
||||
# endif
|
||||
# define bool _Bool
|
||||
# define false 0
|
||||
# define true 1
|
||||
# define __bool_true_false_are_defined 1
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif /* HAVE_SYS_PARAM_H */
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#endif /* MAX */
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#endif /* MIN */
|
||||
])
|
||||
|
||||
AC_C_BIGENDIAN
|
||||
|
||||
AH_TEMPLATE([SYSCALL_HEADER], [Define to header holding system call numbers.])
|
||||
AH_TEMPLATE([USER_HEADER], [Define to header holding USER_REGS_STRUCT.])
|
||||
AH_TEMPLATE([USER_REGS_STRUCT], [Define to structure holding user registers.])
|
||||
AH_TEMPLATE([SYSCALL_NUM_REG], [Define to register holding the system call number.])
|
||||
AH_TEMPLATE([SYSCALL_ARG_REG], [Define to register holding arg0 to system calls.])
|
||||
AH_TEMPLATE([SYSCALL_ARG1_REG], [Define to register holding arg1 to system calls.])
|
||||
AH_TEMPLATE([SYSCALL_ARG2_REG], [Define to register holding arg2 to system calls.])
|
||||
AH_TEMPLATE([SYSCALL_ARG3_REG], [Define to register holding arg3 to system calls.])
|
||||
AH_TEMPLATE([SYSCALL_RET_REG], [Define to register holding value of system calls.])
|
||||
AH_TEMPLATE([STACK_POINTER], [Define to register holding the stack pointer.])
|
||||
AH_TEMPLATE([EXEC_SYSCALL], [Define to number of the `exec' system call.])
|
||||
AH_TEMPLATE([USER_WORD], [Define to word type used by tracees.])
|
||||
AH_TEMPLATE([EXEC_64], [Define to 1 if the system utilizes 64-bit ELF.])
|
||||
AH_TEMPLATE([STACK_GROWS_DOWNWARDS], [Define to 1 if the stack grows downwards.])
|
||||
AH_TEMPLATE([ABI_RED_ZONE], [Define to number of reserved bytes past the stack frame.])
|
||||
AH_TEMPLATE([EXECUTABLE_BASE], [Virtual address for loading PIC executables])
|
||||
AH_TEMPLATE([INTERPRETER_BASE], [Virtual address for loading PIC interpreters])
|
||||
AH_TEMPLATE([CLONE_SYSCALL], [Define to number of the `clone' system call.])
|
||||
AH_TEMPLATE([CLONE3_SYSCALL], [Define to number of the `clone3' system call.])
|
||||
AH_TEMPLATE([READLINK_SYSCALL], [Define to number of the `readlink' system call.])
|
||||
AH_TEMPLATE([READLINKAT_SYSCALL], [Define to number of the `readlinkat' system call.])
|
||||
AH_TEMPLATE([REENTRANT], [Define to 1 if the library is used within a signal handler.])
|
||||
|
||||
AC_CANONICAL_HOST
|
||||
|
||||
# Check whether or not sys/user exists. If it doesn't, try
|
||||
# asm/user.h, and croak if that doesn't exist either.
|
||||
AS_CASE([$host], [*mips*], [], [*],
|
||||
[AC_CHECK_HEADER([sys/user.h], [user_h="<sys/user.h>"],
|
||||
[AC_CHECK_HEADER([asm/user.h], [user_h="<asm/user.h>"],
|
||||
[AC_MSG_ERROR([Can not find working user.h])])])])
|
||||
|
||||
# Look for required tools.
|
||||
|
||||
AC_ARG_VAR([M4], [`m4' preprocessor command.])
|
||||
AC_ARG_VAR([AS], [`as' assembler command.])
|
||||
AC_ARG_VAR([LD], [`ld' linker command.])
|
||||
|
||||
# Check for a working m4.
|
||||
AC_CHECK_PROGS([M4], [gm4 m4],
|
||||
[AC_MSG_ERROR([Cannot find m4])])
|
||||
|
||||
# Check for a working assembler.
|
||||
AC_CHECK_TOOL([AS], [as],
|
||||
[AC_MSG_ERROR([Cannot find a working assembler])])
|
||||
|
||||
# And ar.
|
||||
AC_CHECK_TOOL([AR], [ar],
|
||||
[AC_MSG_ERROR([Cannot find a working ar])])
|
||||
|
||||
# And ld.
|
||||
AC_CHECK_TOOL([LD], [ld],
|
||||
[AC_MSG_ERROR([Cannot find a working linker])])
|
||||
|
||||
# Now check if ld is a C compiler.
|
||||
LDPREFIX=
|
||||
AC_CACHE_CHECK([whether ld is a C compiler],
|
||||
[exec_cv_ld_is_cc],
|
||||
[cat <<_ACEOF > conftest.c
|
||||
AC_LANG_PROGRAM(,)
|
||||
_ACEOF
|
||||
exec_cv_ld_is_cc=yes
|
||||
$LD -c conftest.c -o conftest.$OBJEXT >&AS_MESSAGE_LOG_FD 2>&1 \
|
||||
|| exec_cv_ld_is_cc=no
|
||||
rm -f conftest.c conftest.$OBJEXT])
|
||||
|
||||
# And if as is a C compiler.
|
||||
AC_CACHE_CHECK([whether as is a C compiler],
|
||||
[exec_cv_as_is_cc],
|
||||
[cat <<_ACEOF > conftest.c
|
||||
AC_LANG_PROGRAM(,)
|
||||
_ACEOF
|
||||
exec_cv_as_is_cc=yes
|
||||
$AS -c conftest.c -o conftest.$OBJEXT >&AS_MESSAGE_LOG_FD 2>&1 \
|
||||
|| exec_cv_as_is_cc=no
|
||||
rm -f conftest.c conftest.$OBJEXT])
|
||||
|
||||
# If ld is a C compiler, pass `-nostdlib', `-nostartfiles', and
|
||||
# `-static'. Also, set LDPREFIX to -Wl,
|
||||
AS_IF([test "x$exec_cv_ld_is_cc" = "xyes"],
|
||||
[LOADERFLAGS="$LOADERFLAGS -nostdlib -nostartfiles -static"
|
||||
LDPREFIX=-Wl,])
|
||||
|
||||
# If as is a C compiler, add `-c' to ASFLAGS.
|
||||
AS_IF([test "x$exec_cv_as_is_cc" = "xyes"],
|
||||
[ASFLAGS="$ASFLAGS -c"])
|
||||
|
||||
AC_DEFUN([exec_CHECK_LINUX_CLONE3],
|
||||
[
|
||||
AC_CHECK_DECL([__NR_clone3],
|
||||
[AC_DEFINE([CLONE3_SYSCALL], [__NR_clone3])],
|
||||
[], [[
|
||||
#include <asm/unistd.h>
|
||||
]])
|
||||
])
|
||||
|
||||
AC_DEFUN([exec_CHECK_MIPS_NABI],
|
||||
[
|
||||
AC_CACHE_CHECK([whether MIPS NABI calling convention is used],
|
||||
[exec_cv_mips_nabi],
|
||||
[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <sgidefs.h>
|
||||
]], [[
|
||||
#ifndef __mips64__
|
||||
#if _MIPS_SIM == _ABIO32
|
||||
OABI in use.
|
||||
#endif /* _MIPS_SIM == _ABIO32 */
|
||||
#endif /* !__mips64__ */
|
||||
]])], [exec_cv_mips_nabi=yes],
|
||||
[exec_cv_mips_nabi=no])])
|
||||
|
||||
dnl mips64 systems use N64 calling convention, a variant of nabi
|
||||
dnl calling convention.
|
||||
AS_IF([test "x$exec_cv_mips_nabi" != "xno"],
|
||||
[AC_DEFINE([MIPS_NABI], [1],
|
||||
[Define to 1 if MIPS NABI calling convention is being used.])],
|
||||
[OBJS="$OBJS mipsfpu.o"])
|
||||
])
|
||||
|
||||
# Determine the system type and define appropriate macros.
|
||||
exec_loader=
|
||||
is_mips=
|
||||
OBJS="exec.o trace.o"
|
||||
DADDI_BROKEN=no
|
||||
|
||||
AS_CASE([$host], [x86_64-*linux*],
|
||||
[AC_CHECK_MEMBER([struct user_regs_struct.rdi],
|
||||
[AC_DEFINE([SYSCALL_HEADER], [<asm/unistd.h>])
|
||||
AC_DEFINE_UNQUOTED([USER_HEADER], [$user_h])
|
||||
AC_DEFINE([USER_REGS_STRUCT], [struct user_regs_struct])
|
||||
AC_DEFINE([SYSCALL_NUM_REG], [orig_rax])
|
||||
AC_DEFINE([SYSCALL_RET_REG], [rax])
|
||||
AC_DEFINE([SYSCALL_ARG_REG], [rdi])
|
||||
AC_DEFINE([SYSCALL_ARG1_REG], [rsi])
|
||||
AC_DEFINE([SYSCALL_ARG2_REG], [rdx])
|
||||
AC_DEFINE([SYSCALL_ARG3_REG], [r10])
|
||||
AC_DEFINE([STACK_POINTER], [rsp])
|
||||
AC_DEFINE([EXEC_SYSCALL], [__NR_execve])
|
||||
AC_DEFINE([USER_WORD], [uintptr_t])
|
||||
AC_DEFINE([EXEC_64], [1])
|
||||
AC_DEFINE([ABI_RED_ZONE], [128])
|
||||
AC_DEFINE([EXECUTABLE_BASE], [0x555555554000])
|
||||
AC_DEFINE([INTERPRETER_BASE], [0x600000000000])
|
||||
AC_DEFINE([STACK_GROWS_DOWNWARDS], [1])
|
||||
AC_DEFINE([CLONE_SYSCALL], [__NR_clone])
|
||||
AC_DEFINE([READLINK_SYSCALL], [__NR_readlink])
|
||||
AC_DEFINE([READLINKAT_SYSCALL], [__NR_readlinkat])
|
||||
exec_CHECK_LINUX_CLONE3
|
||||
# Make sure the loader doesn't conflict with other position
|
||||
# dependent code.
|
||||
LOADERFLAGS="$LOADERFLAGS $LDPREFIX-Ttext=0x200000000000"
|
||||
exec_loader=loader-x86_64.s],
|
||||
[AC_MSG_ERROR([Missing `rdi' in user_regs_struct])],
|
||||
[[
|
||||
#include $user_h
|
||||
]])], [i[[34567]]86-*linux*],
|
||||
[AC_CHECK_MEMBER([struct user_regs_struct.edi],
|
||||
[AC_DEFINE([SYSCALL_HEADER], [<asm/unistd.h>])
|
||||
AC_DEFINE_UNQUOTED([USER_HEADER], [$user_h])
|
||||
AC_DEFINE([USER_REGS_STRUCT], [struct user_regs_struct])
|
||||
AC_DEFINE([SYSCALL_NUM_REG], [orig_eax])
|
||||
AC_DEFINE([SYSCALL_RET_REG], [eax])
|
||||
AC_DEFINE([SYSCALL_ARG_REG], [ebx])
|
||||
AC_DEFINE([SYSCALL_ARG1_REG], [ecx])
|
||||
AC_DEFINE([SYSCALL_ARG2_REG], [edx])
|
||||
AC_DEFINE([SYSCALL_ARG3_REG], [esi])
|
||||
AC_DEFINE([STACK_POINTER], [esp])
|
||||
AC_DEFINE([EXEC_SYSCALL], [__NR_execve])
|
||||
AC_DEFINE([USER_WORD], [uintptr_t])
|
||||
AC_DEFINE([EXECUTABLE_BASE], [0x0f000000])
|
||||
AC_DEFINE([INTERPRETER_BASE], [0xaf000000])
|
||||
AC_DEFINE([STACK_GROWS_DOWNWARDS], [1])
|
||||
AC_DEFINE([CLONE_SYSCALL], [__NR_clone])
|
||||
AC_DEFINE([READLINK_SYSCALL], [__NR_readlink])
|
||||
AC_DEFINE([READLINKAT_SYSCALL], [__NR_readlinkat])
|
||||
exec_CHECK_LINUX_CLONE3
|
||||
# Make sure the loader doesn't conflict with other position
|
||||
# dependent code.
|
||||
LOADERFLAGS="$LOADERFLAGS $LDPREFIX-Ttext=0xa0000000"
|
||||
exec_loader=loader-x86.s],
|
||||
[AC_MSG_ERROR([Missing `edi' in user_regs_struct])],
|
||||
[[
|
||||
#include $user_h
|
||||
]])], [aarch64-*linux*],
|
||||
[AC_CHECK_MEMBER([struct user_regs_struct.sp],
|
||||
[AC_DEFINE([SYSCALL_HEADER], [<asm/unistd.h>])
|
||||
AC_DEFINE_UNQUOTED([USER_HEADER], [$user_h])
|
||||
AC_DEFINE([USER_REGS_STRUCT], [struct user_regs_struct])
|
||||
AC_DEFINE([SYSCALL_NUM_REG], [[regs[8]]])
|
||||
AC_DEFINE([SYSCALL_RET_REG], [[regs[0]]])
|
||||
AC_DEFINE([SYSCALL_ARG_REG], [[regs[0]]])
|
||||
AC_DEFINE([SYSCALL_ARG1_REG], [[regs[1]]])
|
||||
AC_DEFINE([SYSCALL_ARG2_REG], [[regs[2]]])
|
||||
AC_DEFINE([SYSCALL_ARG3_REG], [[regs[3]]])
|
||||
AC_DEFINE([STACK_POINTER], [sp])
|
||||
AC_DEFINE([EXEC_SYSCALL], [__NR_execve])
|
||||
AC_DEFINE([USER_WORD], [uintptr_t])
|
||||
AC_DEFINE([EXEC_64], [1])
|
||||
AC_DEFINE([EXECUTABLE_BASE], [0x3000000000])
|
||||
AC_DEFINE([INTERPRETER_BASE], [0x3f00000000])
|
||||
AC_DEFINE([STACK_GROWS_DOWNWARDS], [1])
|
||||
AC_DEFINE([CLONE_SYSCALL], [__NR_clone])
|
||||
# Note that aarch64 has no `readlink'.
|
||||
AC_DEFINE([READLINKAT_SYSCALL], [__NR_readlinkat])
|
||||
exec_CHECK_LINUX_CLONE3
|
||||
# Make sure the loader doesn't conflict with other position
|
||||
# dependent code. ARM places rather significant restrictions on
|
||||
# virtual addresses for a 64 bit architecture.
|
||||
LOADERFLAGS="$LOADERFLAGS $LDPREFIX-Ttext=0x2000000000"
|
||||
exec_loader=loader-aarch64.s],
|
||||
[AC_MSG_ERROR([Missing `sp' in user_regs_struct])],
|
||||
[[
|
||||
#include $user_h
|
||||
]])], [arm*linux*eabi* | armv7*linux*],
|
||||
[AC_CHECK_MEMBER([struct user_regs.uregs],
|
||||
[AC_DEFINE([SYSCALL_HEADER], [<asm/unistd.h>])
|
||||
AC_DEFINE_UNQUOTED([USER_HEADER], [$user_h])
|
||||
AC_DEFINE([USER_REGS_STRUCT], [struct user_regs])
|
||||
AC_DEFINE([SYSCALL_NUM_REG], [[uregs[7]]])
|
||||
AC_DEFINE([SYSCALL_RET_REG], [[uregs[0]]])
|
||||
AC_DEFINE([SYSCALL_ARG_REG], [[uregs[0]]])
|
||||
AC_DEFINE([SYSCALL_ARG1_REG], [[uregs[1]]])
|
||||
AC_DEFINE([SYSCALL_ARG2_REG], [[uregs[2]]])
|
||||
AC_DEFINE([SYSCALL_ARG3_REG], [[uregs[3]]])
|
||||
AC_DEFINE([STACK_POINTER], [[uregs[13]]])
|
||||
AC_DEFINE([EXEC_SYSCALL], [__NR_execve])
|
||||
AC_DEFINE([USER_WORD], [uintptr_t])
|
||||
AC_DEFINE([EXECUTABLE_BASE], [0x0f000000])
|
||||
AC_DEFINE([INTERPRETER_BASE], [0x1f000000])
|
||||
AC_DEFINE([STACK_GROWS_DOWNWARDS], [1])
|
||||
AC_DEFINE([CLONE_SYSCALL], [__NR_clone])
|
||||
AC_DEFINE([READLINK_SYSCALL], [__NR_readlink])
|
||||
AC_DEFINE([READLINKAT_SYSCALL], [__NR_readlinkat])
|
||||
exec_CHECK_LINUX_CLONE3
|
||||
LOADERFLAGS="$LOADERFLAGS $LDPREFIX-Ttext=0x20000000"
|
||||
exec_loader=loader-armeabi.s],
|
||||
[AC_CHECK_MEMBER([struct pt_regs.uregs],
|
||||
[AC_DEFINE([SYSCALL_HEADER], [<asm/unistd.h>])
|
||||
AC_DEFINE_UNQUOTED([USER_HEADER], [<asm/ptrace.h>])
|
||||
AC_DEFINE([USER_REGS_STRUCT], [struct pt_regs])
|
||||
AC_DEFINE([SYSCALL_NUM_REG], [[uregs[7]]])
|
||||
AC_DEFINE([SYSCALL_RET_REG], [[uregs[0]]])
|
||||
AC_DEFINE([SYSCALL_ARG_REG], [[uregs[0]]])
|
||||
AC_DEFINE([SYSCALL_ARG1_REG], [[uregs[1]]])
|
||||
AC_DEFINE([SYSCALL_ARG2_REG], [[uregs[2]]])
|
||||
AC_DEFINE([SYSCALL_ARG3_REG], [[uregs[3]]])
|
||||
AC_DEFINE([STACK_POINTER], [[uregs[13]]])
|
||||
AC_DEFINE([EXEC_SYSCALL], [__NR_execve])
|
||||
AC_DEFINE([USER_WORD], [uintptr_t])
|
||||
AC_DEFINE([EXECUTABLE_BASE], [0x0f000000])
|
||||
AC_DEFINE([INTERPRETER_BASE], [0x1f000000])
|
||||
AC_DEFINE([STACK_GROWS_DOWNWARDS], [1])
|
||||
AC_DEFINE([CLONE_SYSCALL], [__NR_clone])
|
||||
AC_DEFINE([READLINK_SYSCALL], [__NR_readlink])
|
||||
AC_DEFINE([READLINKAT_SYSCALL], [__NR_readlinkat])
|
||||
exec_CHECK_LINUX_CLONE3
|
||||
LOADERFLAGS="$LOADERFLAGS $LDPREFIX-Ttext=0x20000000"
|
||||
exec_loader=loader-armeabi.s],
|
||||
[AC_MSG_ERROR([Missing `uregs' in user_regs_struct or pt_regs])],
|
||||
[[
|
||||
#include <asm/ptrace.h>
|
||||
]])],
|
||||
[[
|
||||
#include $user_h
|
||||
]])], [mipsel*linux*],
|
||||
[AC_DEFINE([SYSCALL_HEADER], [<asm/unistd.h>])
|
||||
AC_DEFINE([USER_HEADER], ["mipsel-user.h"])
|
||||
AC_DEFINE([USER_REGS_STRUCT], [struct mipsel_regs])
|
||||
AC_DEFINE([SYSCALL_NUM_REG], [[gregs[2]]]) # v0
|
||||
AC_DEFINE([SYSCALL_RET_REG], [[gregs[4]]]) # a0
|
||||
AC_DEFINE([SYSCALL_ARG_REG], [[gregs[4]]]) # a0
|
||||
AC_DEFINE([SYSCALL_ARG1_REG], [[gregs[5]]]) # a1
|
||||
AC_DEFINE([SYSCALL_ARG2_REG], [[gregs[4]]]) # a2
|
||||
AC_DEFINE([SYSCALL_ARG3_REG], [[gregs[5]]]) # a3
|
||||
AC_DEFINE([STACK_POINTER], [[gregs[29]]]) # sp
|
||||
AC_DEFINE([EXEC_SYSCALL], [__NR_execve])
|
||||
AC_DEFINE([USER_WORD], [uintptr_t])
|
||||
AC_DEFINE([EXECUTABLE_BASE], [0x0f000000])
|
||||
AC_DEFINE([INTERPRETER_BASE], [0x1f000000])
|
||||
AC_DEFINE([STACK_GROWS_DOWNWARDS], [1])
|
||||
AC_DEFINE([CLONE_SYSCALL], [__NR_clone])
|
||||
AC_DEFINE([READLINK_SYSCALL], [__NR_readlink])
|
||||
AC_DEFINE([READLINKAT_SYSCALL], [__NR_readlinkat])
|
||||
AC_CHECK_DECL([_MIPS_SIM], [exec_CHECK_MIPS_NABI],
|
||||
[AC_MSG_ERROR([_MIPS_SIM could not be determined]),
|
||||
[[
|
||||
#include <sgidefs.h>
|
||||
]]])
|
||||
exec_CHECK_LINUX_CLONE3
|
||||
LOADERFLAGS="$LOADERFLAGS $LDPREFIX-Ttext=0x20000000"
|
||||
is_mips=yes
|
||||
exec_loader=loader-mipsel.s], [mips64el*linux*],
|
||||
[AC_DEFINE([SYSCALL_HEADER], [<asm/unistd.h>])
|
||||
AC_DEFINE([USER_HEADER], ["mipsel-user.h"])
|
||||
AC_DEFINE([USER_REGS_STRUCT], [struct mipsel_regs])
|
||||
AC_DEFINE([SYSCALL_NUM_REG], [[gregs[2]]]) # v0
|
||||
AC_DEFINE([SYSCALL_RET_REG], [[gregs[4]]]) # a0
|
||||
AC_DEFINE([SYSCALL_ARG_REG], [[gregs[4]]]) # a0
|
||||
AC_DEFINE([SYSCALL_ARG1_REG], [[gregs[5]]]) # a1
|
||||
AC_DEFINE([SYSCALL_ARG2_REG], [[gregs[4]]]) # a2
|
||||
AC_DEFINE([SYSCALL_ARG3_REG], [[gregs[5]]]) # a3
|
||||
AC_DEFINE([STACK_POINTER], [[gregs[29]]]) # sp
|
||||
AC_DEFINE([EXEC_SYSCALL], [__NR_execve])
|
||||
AC_DEFINE([USER_WORD], [uintptr_t])
|
||||
AC_DEFINE([EXEC_64], [1])
|
||||
AC_DEFINE([EXECUTABLE_BASE], [0x400000])
|
||||
AC_DEFINE([INTERPRETER_BASE], [0x3f00000000])
|
||||
AC_DEFINE([STACK_GROWS_DOWNWARDS], [1])
|
||||
AC_DEFINE([CLONE_SYSCALL], [__NR_clone])
|
||||
AC_DEFINE([READLINK_SYSCALL], [__NR_readlink])
|
||||
AC_DEFINE([READLINKAT_SYSCALL], [__NR_readlinkat])
|
||||
AC_CACHE_CHECK([whether as understands `daddi'],
|
||||
[exec_cv_as_daddi],
|
||||
[exec_cv_as_daddi=no
|
||||
cat <<_ACEOF >conftest.s
|
||||
.section text
|
||||
.global __start
|
||||
__start:
|
||||
li $t0, 0
|
||||
li $t1, 0
|
||||
daddi $t0, $t1, 1
|
||||
daddi $t0, $t1, -1
|
||||
daddi $t0, -1
|
||||
daddi $t0, 1
|
||||
|
||||
_ACEOF
|
||||
$AS $ASFLAGS conftest.s -o conftest.$OBJEXT \
|
||||
>&AS_MESSAGE_LOG_FD 2>&1 \
|
||||
&& exec_cv_as_daddi=yes
|
||||
rm -f conftest.s conftest.$OBJEXT])
|
||||
AS_IF([test "x$exec_cv_as_daddi" != "xyes"],
|
||||
[DADDI_BROKEN=yes])
|
||||
exec_CHECK_LINUX_CLONE3
|
||||
exec_CHECK_MIPS_NABI
|
||||
LOADERFLAGS="$LOADERFLAGS $LDPREFIX-Ttext=0x3e00000000"
|
||||
is_mips=yes
|
||||
exec_loader=loader-mips64el.s], [*],
|
||||
[AC_MSG_ERROR([Please port libexec to $host])])
|
||||
|
||||
AC_SUBST([DADDI_BROKEN])
|
||||
|
||||
MIPS_N32=$exec_cv_mips_nabi
|
||||
|
||||
AC_ARG_VAR([LOADERFLAGS], [Flags used to link the loader.])
|
||||
AC_ARG_VAR([ARFLAGS], [Flags for the archiver.])
|
||||
AC_ARG_VAR([ASFLAGS], [Flags for the assembler.])
|
||||
|
||||
# Make the assembler optimize for code size. Don't do this on MIPS,
|
||||
# as the assembler code manages branch delays manually.
|
||||
|
||||
AC_CACHE_CHECK([whether as understands -O],
|
||||
[exec_cv_as_O],
|
||||
[exec_cv_as_O=no
|
||||
cat <<_ACEOF >conftest.s
|
||||
.section text
|
||||
.global _start
|
||||
_start:
|
||||
|
||||
_ACEOF
|
||||
$AS $ASFLAGS -O conftest.s -o conftest.$OBJEXT \
|
||||
>&AS_MESSAGE_LOG_FD 2>&1 \
|
||||
&& exec_cv_as_O=yes
|
||||
rm -f conftest.s conftest.$OBJEXT])
|
||||
|
||||
AS_IF([test "$exec_cv_as_O" = "yes" \
|
||||
&& test "$is_mips" != "yes"],
|
||||
[ASFLAGS="$ASFLAGS -O"])
|
||||
|
||||
# Make the assembler generate debug information.
|
||||
|
||||
AC_CACHE_CHECK([whether as understands -g],
|
||||
[exec_cv_as_g],
|
||||
[exec_cv_as_g=no
|
||||
cat <<_ACEOF >conftest.s
|
||||
.section text
|
||||
.global _start
|
||||
_start:
|
||||
|
||||
_ACEOF
|
||||
$AS $ASFLAGS -g conftest.s -o conftest.$OBJEXT \
|
||||
>&AS_MESSAGE_LOG_FD 2>&1 \
|
||||
&& exec_cv_as_g=yes
|
||||
rm -f conftest.s conftest.$OBJEXT])
|
||||
AS_IF([test "$exec_cv_as_g" = "yes"], [ASFLAGS="$ASFLAGS -g"])
|
||||
|
||||
# Check for the ability to automatically generate dependencies for C
|
||||
# source files.
|
||||
AUTO_DEPEND=no
|
||||
AS_IF([test "x$GCC" = xyes],
|
||||
[AC_CACHE_CHECK([whether gcc understands -MMD -MF],
|
||||
[exec_cv_autodepend],
|
||||
[SAVE_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -MMD -MF deps.d -MP"
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],
|
||||
[exec_cv_autodepend=yes],
|
||||
[exec_cv_autodepend=no])
|
||||
CFLAGS="$SAVE_CFLAGS"
|
||||
test -f deps.d || emacs_cv_autodepend=no
|
||||
rm -rf deps.d])
|
||||
AS_IF([test "x$exec_cv_autodepend" = xyes],
|
||||
[AUTO_DEPEND=yes
|
||||
AS_MKDIR_P([deps])])])
|
||||
|
||||
# Now check for some other stuff.
|
||||
|
||||
AC_CACHE_CHECK([for 'find' args to delete a file],
|
||||
[exec_cv_find_delete],
|
||||
[AS_IF([touch conftest.tmp && find conftest.tmp -delete 2>/dev/null &&
|
||||
test ! -f conftest.tmp], [exec_cv_find_delete="-delete"],
|
||||
[exec_cv_find_delete="-exec rm -f {} ';'"])])
|
||||
FIND_DELETE=$exec_cv_find_delete
|
||||
AC_SUBST([FIND_DELETE])
|
||||
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_FILES([Makefile config-mips.m4])
|
||||
|
||||
AC_SUBST([AUTO_DEPEND])
|
||||
AC_SUBST([LOADERFLAGS])
|
||||
AC_SUBST([ARFLAGS])
|
||||
AC_SUBST([ASFLAGS])
|
||||
AC_SUBST([exec_loader])
|
||||
AC_SUBST([MIPS_N32])
|
||||
AC_SUBST([OBJS])
|
||||
|
||||
AC_OUTPUT
|
21
exec/deps.mk
Normal file
21
exec/deps.mk
Normal file
|
@ -0,0 +1,21 @@
|
|||
### deps.mk
|
||||
|
||||
## Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
## This file is part of GNU Emacs.
|
||||
|
||||
## GNU Emacs is free software: you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published by
|
||||
## the Free Software Foundation, either version 3 of the License, or
|
||||
## (at your option) any later version.
|
||||
##
|
||||
## GNU Emacs is distributed in the hope that it will be useful,
|
||||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License
|
||||
## along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
exec.o: exec.h config.h
|
||||
trace.o: exec.h config.h
|
1235
exec/exec.c
Normal file
1235
exec/exec.c
Normal file
File diff suppressed because it is too large
Load diff
201
exec/exec.h
Normal file
201
exec/exec.h
Normal file
|
@ -0,0 +1,201 @@
|
|||
/* Program execution for Emacs.
|
||||
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
|
||||
|
||||
#ifndef _EXEC_H_
|
||||
#define _EXEC_H_
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif /* HAVE_STDINT_H */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include USER_HEADER
|
||||
|
||||
/* Define a replacement for `uint64_t' if it's not present in the C
|
||||
library. */
|
||||
|
||||
#ifndef UINT64_MAX
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t word1;
|
||||
uint32_t word2;
|
||||
} xint64_t;
|
||||
|
||||
#else /* UINT64_MAX */
|
||||
typedef uint64_t xint64_t;
|
||||
#endif /* !UINT64_MAX */
|
||||
|
||||
|
||||
|
||||
/* 32-bit ELF headers. */
|
||||
|
||||
struct elf_header_32
|
||||
{
|
||||
unsigned char e_ident[16];
|
||||
uint16_t e_type;
|
||||
uint16_t e_machine;
|
||||
uint32_t e_version;
|
||||
uint32_t e_entry;
|
||||
uint32_t e_phoff;
|
||||
uint32_t e_shoff;
|
||||
uint32_t e_flags;
|
||||
uint16_t e_ehsize;
|
||||
uint16_t e_phentsize;
|
||||
uint16_t e_phnum;
|
||||
uint16_t e_shentsize;
|
||||
uint16_t e_shnum;
|
||||
uint16_t e_shstrndx;
|
||||
};
|
||||
|
||||
struct program_header_32
|
||||
{
|
||||
uint32_t p_type;
|
||||
uint32_t p_offset;
|
||||
uint32_t p_vaddr;
|
||||
uint32_t p_paddr;
|
||||
uint32_t p_filesz;
|
||||
uint32_t p_memsz;
|
||||
uint32_t p_flags;
|
||||
uint32_t p_align;
|
||||
};
|
||||
|
||||
struct dt_entry_32
|
||||
{
|
||||
uint32_t d_tag;
|
||||
uint32_t d_val;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct elf_header_64
|
||||
{
|
||||
unsigned char e_ident[16];
|
||||
uint16_t e_type;
|
||||
uint16_t e_machine;
|
||||
uint32_t e_version;
|
||||
xint64_t e_entry;
|
||||
xint64_t e_phoff;
|
||||
xint64_t e_shoff;
|
||||
uint32_t e_flags;
|
||||
uint16_t e_ehsize;
|
||||
uint16_t e_phentsize;
|
||||
uint16_t e_phnum;
|
||||
uint16_t e_shentsize;
|
||||
uint16_t e_shnum;
|
||||
uint16_t e_shstrndx;
|
||||
};
|
||||
|
||||
struct program_header_64
|
||||
{
|
||||
uint32_t p_type;
|
||||
uint32_t p_flags;
|
||||
xint64_t p_offset;
|
||||
xint64_t p_vaddr;
|
||||
xint64_t p_paddr;
|
||||
xint64_t p_filesz;
|
||||
xint64_t p_memsz;
|
||||
xint64_t p_align;
|
||||
};
|
||||
|
||||
struct dt_entry_64
|
||||
{
|
||||
xint64_t d_tag;
|
||||
xint64_t d_val;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Define some types to the correct values. */
|
||||
|
||||
#ifdef EXEC_64
|
||||
typedef struct elf_header_64 elf_header;
|
||||
typedef struct program_header_64 program_header;
|
||||
typedef struct dt_entry_64 dt_entry;
|
||||
#else /* !EXEC_64 */
|
||||
typedef struct elf_header_32 elf_header;
|
||||
typedef struct program_header_32 program_header;
|
||||
typedef struct dt_entry_32 dt_entry;
|
||||
#endif /* EXEC_64 */
|
||||
|
||||
|
||||
|
||||
/* Defined in trace.c. */
|
||||
|
||||
/* Structure describing a process being traced. */
|
||||
|
||||
struct exec_tracee
|
||||
{
|
||||
/* The next process being traced. */
|
||||
struct exec_tracee *next;
|
||||
|
||||
/* The thread ID of this process. */
|
||||
pid_t pid;
|
||||
|
||||
/* Whether or not the tracee is currently waiting for a system call
|
||||
to complete. */
|
||||
bool waiting_for_syscall : 1;
|
||||
|
||||
/* Whether or not the tracee has been created but is not yet
|
||||
processed by `handle_clone'. */
|
||||
bool new_child : 1;
|
||||
|
||||
#ifndef REENTRANT
|
||||
/* Name of the executable being run. */
|
||||
char *exec_file;
|
||||
#endif /* !REENTRANT */
|
||||
};
|
||||
|
||||
|
||||
|
||||
#ifdef __aarch64__
|
||||
|
||||
extern int aarch64_get_regs (pid_t, USER_REGS_STRUCT *);
|
||||
extern int aarch64_set_regs (pid_t, USER_REGS_STRUCT *, bool);
|
||||
|
||||
#endif /* __aarch64__ */
|
||||
|
||||
|
||||
|
||||
extern USER_WORD user_alloca (struct exec_tracee *, USER_REGS_STRUCT *,
|
||||
USER_REGS_STRUCT *, USER_WORD);
|
||||
extern int user_copy (struct exec_tracee *, const unsigned char *,
|
||||
USER_WORD, USER_WORD);
|
||||
extern void exec_init (const char *);
|
||||
|
||||
|
||||
|
||||
extern int tracing_execve (const char *, char *const *,
|
||||
char *const *);
|
||||
extern int after_fork (pid_t);
|
||||
extern pid_t exec_waitpid (pid_t, int *, int);
|
||||
|
||||
|
||||
|
||||
/* Defined in exec.c. */
|
||||
|
||||
extern char *exec_0 (char *, struct exec_tracee *,
|
||||
size_t *, USER_REGS_STRUCT *);
|
||||
|
||||
|
||||
|
||||
#endif /* _EXEC_H_ */
|
94
exec/exec1.c
Normal file
94
exec/exec1.c
Normal file
|
@ -0,0 +1,94 @@
|
|||
/* Program execution for Emacs.
|
||||
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <config.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "exec.h"
|
||||
|
||||
/* exec1 is a program which takes another program and its arguments,
|
||||
forks, and executes that program, all while tracing it and its
|
||||
children to use the program execution mechanism defined in exec.c.
|
||||
|
||||
This is necessary to bypass security restrictions which prohibit
|
||||
Emacs from loading executables from certain directories, by, in
|
||||
effect, replacing the executable loader in the Linux kernel. */
|
||||
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
pid_t pid, pid1;
|
||||
extern char **environ;
|
||||
int wstatus;
|
||||
|
||||
pid1 = getpid ();
|
||||
pid = fork ();
|
||||
|
||||
if (!pid)
|
||||
{
|
||||
/* Set the process group used to the parent. */
|
||||
if (setpgid (0, pid1))
|
||||
perror ("setpgid");
|
||||
|
||||
tracing_execve (argv[2], argv + 2, environ);
|
||||
|
||||
/* An error occured. Exit with failure. */
|
||||
exit (127);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Provide the file name of the loader. */
|
||||
exec_init (argv[1]);
|
||||
|
||||
if (after_fork (pid))
|
||||
exit (127);
|
||||
|
||||
/* Start waiting for the process to exit. */
|
||||
|
||||
while (true)
|
||||
{
|
||||
pid1 = exec_waitpid (-1, &wstatus, 0);
|
||||
|
||||
/* If the child process exits normally, exit with its status
|
||||
code. If not, raise the signal that caused it to
|
||||
exit. */
|
||||
|
||||
if (pid == pid1)
|
||||
{
|
||||
if (WIFEXITED (wstatus))
|
||||
exit (WEXITSTATUS (wstatus));
|
||||
else /* if WIFSIGNALED (wstatus) */
|
||||
{
|
||||
raise (WTERMSIG (wstatus));
|
||||
|
||||
/* Just in case the signal raised doesn't cause an
|
||||
exit. */
|
||||
exit (127);
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise, continue looping. */
|
||||
}
|
||||
}
|
||||
}
|
541
exec/install-sh
Executable file
541
exec/install-sh
Executable file
|
@ -0,0 +1,541 @@
|
|||
#!/usr/bin/sh
|
||||
# install - install a program, script, or datafile
|
||||
|
||||
scriptversion=2020-11-14.01; # UTC
|
||||
|
||||
# This originates from X11R5 (mit/util/scripts/install.sh), which was
|
||||
# later released in X11R6 (xc/config/util/install.sh) with the
|
||||
# following copyright and license.
|
||||
#
|
||||
# Copyright (C) 1994 X Consortium
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
|
||||
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# Except as contained in this notice, the name of the X Consortium shall not
|
||||
# be used in advertising or otherwise to promote the sale, use or other deal-
|
||||
# ings in this Software without prior written authorization from the X Consor-
|
||||
# tium.
|
||||
#
|
||||
#
|
||||
# FSF changes to this file are in the public domain.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# 'make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch.
|
||||
|
||||
tab=' '
|
||||
nl='
|
||||
'
|
||||
IFS=" $tab$nl"
|
||||
|
||||
# Set DOITPROG to "echo" to test this script.
|
||||
|
||||
doit=${DOITPROG-}
|
||||
doit_exec=${doit:-exec}
|
||||
|
||||
# Put in absolute file names if you don't have them in your path;
|
||||
# or use environment vars.
|
||||
|
||||
chgrpprog=${CHGRPPROG-chgrp}
|
||||
chmodprog=${CHMODPROG-chmod}
|
||||
chownprog=${CHOWNPROG-chown}
|
||||
cmpprog=${CMPPROG-cmp}
|
||||
cpprog=${CPPROG-cp}
|
||||
mkdirprog=${MKDIRPROG-mkdir}
|
||||
mvprog=${MVPROG-mv}
|
||||
rmprog=${RMPROG-rm}
|
||||
stripprog=${STRIPPROG-strip}
|
||||
|
||||
posix_mkdir=
|
||||
|
||||
# Desired mode of installed file.
|
||||
mode=0755
|
||||
|
||||
# Create dirs (including intermediate dirs) using mode 755.
|
||||
# This is like GNU 'install' as of coreutils 8.32 (2020).
|
||||
mkdir_umask=22
|
||||
|
||||
backupsuffix=
|
||||
chgrpcmd=
|
||||
chmodcmd=$chmodprog
|
||||
chowncmd=
|
||||
mvcmd=$mvprog
|
||||
rmcmd="$rmprog -f"
|
||||
stripcmd=
|
||||
|
||||
src=
|
||||
dst=
|
||||
dir_arg=
|
||||
dst_arg=
|
||||
|
||||
copy_on_change=false
|
||||
is_target_a_directory=possibly
|
||||
|
||||
usage="\
|
||||
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
|
||||
or: $0 [OPTION]... SRCFILES... DIRECTORY
|
||||
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
|
||||
or: $0 [OPTION]... -d DIRECTORIES...
|
||||
|
||||
In the 1st form, copy SRCFILE to DSTFILE.
|
||||
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
|
||||
In the 4th, create DIRECTORIES.
|
||||
|
||||
Options:
|
||||
--help display this help and exit.
|
||||
--version display version info and exit.
|
||||
|
||||
-c (ignored)
|
||||
-C install only if different (preserve data modification time)
|
||||
-d create directories instead of installing files.
|
||||
-g GROUP $chgrpprog installed files to GROUP.
|
||||
-m MODE $chmodprog installed files to MODE.
|
||||
-o USER $chownprog installed files to USER.
|
||||
-p pass -p to $cpprog.
|
||||
-s $stripprog installed files.
|
||||
-S SUFFIX attempt to back up existing files, with suffix SUFFIX.
|
||||
-t DIRECTORY install into DIRECTORY.
|
||||
-T report an error if DSTFILE is a directory.
|
||||
|
||||
Environment variables override the default commands:
|
||||
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
|
||||
RMPROG STRIPPROG
|
||||
|
||||
By default, rm is invoked with -f; when overridden with RMPROG,
|
||||
it's up to you to specify -f if you want it.
|
||||
|
||||
If -S is not specified, no backups are attempted.
|
||||
|
||||
Email bug reports to bug-automake@gnu.org.
|
||||
Automake home page: https://www.gnu.org/software/automake/
|
||||
"
|
||||
|
||||
while test $# -ne 0; do
|
||||
case $1 in
|
||||
-c) ;;
|
||||
|
||||
-C) copy_on_change=true;;
|
||||
|
||||
-d) dir_arg=true;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift;;
|
||||
|
||||
--help) echo "$usage"; exit $?;;
|
||||
|
||||
-m) mode=$2
|
||||
case $mode in
|
||||
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
|
||||
echo "$0: invalid mode: $mode" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift;;
|
||||
|
||||
-p) cpprog="$cpprog -p";;
|
||||
|
||||
-s) stripcmd=$stripprog;;
|
||||
|
||||
-S) backupsuffix="$2"
|
||||
shift;;
|
||||
|
||||
-t)
|
||||
is_target_a_directory=always
|
||||
dst_arg=$2
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-T) is_target_a_directory=never;;
|
||||
|
||||
--version) echo "$0 $scriptversion"; exit $?;;
|
||||
|
||||
--) shift
|
||||
break;;
|
||||
|
||||
-*) echo "$0: invalid option: $1" >&2
|
||||
exit 1;;
|
||||
|
||||
*) break;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# We allow the use of options -d and -T together, by making -d
|
||||
# take the precedence; this is for compatibility with GNU install.
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
if test -n "$dst_arg"; then
|
||||
echo "$0: target directory not allowed when installing a directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
|
||||
# When -d is used, all remaining arguments are directories to create.
|
||||
# When -t is used, the destination is already specified.
|
||||
# Otherwise, the last argument is the destination. Remove it from $@.
|
||||
for arg
|
||||
do
|
||||
if test -n "$dst_arg"; then
|
||||
# $@ is not empty: it contains at least $arg.
|
||||
set fnord "$@" "$dst_arg"
|
||||
shift # fnord
|
||||
fi
|
||||
shift # arg
|
||||
dst_arg=$arg
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
if test $# -eq 0; then
|
||||
if test -z "$dir_arg"; then
|
||||
echo "$0: no input file specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
# It's OK to call 'install-sh -d' without argument.
|
||||
# This can happen when creating conditional directories.
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
if test $# -gt 1 || test "$is_target_a_directory" = always; then
|
||||
if test ! -d "$dst_arg"; then
|
||||
echo "$0: $dst_arg: Is not a directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
do_exit='(exit $ret); exit $ret'
|
||||
trap "ret=129; $do_exit" 1
|
||||
trap "ret=130; $do_exit" 2
|
||||
trap "ret=141; $do_exit" 13
|
||||
trap "ret=143; $do_exit" 15
|
||||
|
||||
# Set umask so as not to create temps with too-generous modes.
|
||||
# However, 'strip' requires both read and write access to temps.
|
||||
case $mode in
|
||||
# Optimize common cases.
|
||||
*644) cp_umask=133;;
|
||||
*755) cp_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw='% 200'
|
||||
fi
|
||||
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
|
||||
*)
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw=,u+rw
|
||||
fi
|
||||
cp_umask=$mode$u_plus_rw;;
|
||||
esac
|
||||
fi
|
||||
|
||||
for src
|
||||
do
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $src in
|
||||
-* | [=\(\)!]) src=./$src;;
|
||||
esac
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
dst=$src
|
||||
dstdir=$dst
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
# Don't chown directories that already exist.
|
||||
if test $dstdir_status = 0; then
|
||||
chowncmd=""
|
||||
fi
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
if test ! -f "$src" && test ! -d "$src"; then
|
||||
echo "$0: $src does not exist." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test -z "$dst_arg"; then
|
||||
echo "$0: no destination specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
dst=$dst_arg
|
||||
|
||||
# If destination is a directory, append the input filename.
|
||||
if test -d "$dst"; then
|
||||
if test "$is_target_a_directory" = never; then
|
||||
echo "$0: $dst_arg: Is a directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
dstdir=$dst
|
||||
dstbase=`basename "$src"`
|
||||
case $dst in
|
||||
*/) dst=$dst$dstbase;;
|
||||
*) dst=$dst/$dstbase;;
|
||||
esac
|
||||
dstdir_status=0
|
||||
else
|
||||
dstdir=`dirname "$dst"`
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
fi
|
||||
fi
|
||||
|
||||
case $dstdir in
|
||||
*/) dstdirslash=$dstdir;;
|
||||
*) dstdirslash=$dstdir/;;
|
||||
esac
|
||||
|
||||
obsolete_mkdir_used=false
|
||||
|
||||
if test $dstdir_status != 0; then
|
||||
case $posix_mkdir in
|
||||
'')
|
||||
# With -d, create the new directory with the user-specified mode.
|
||||
# Otherwise, rely on $mkdir_umask.
|
||||
if test -n "$dir_arg"; then
|
||||
mkdir_mode=-m$mode
|
||||
else
|
||||
mkdir_mode=
|
||||
fi
|
||||
|
||||
posix_mkdir=false
|
||||
# The $RANDOM variable is not portable (e.g., dash). Use it
|
||||
# here however when possible just to lower collision chance.
|
||||
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
|
||||
|
||||
trap '
|
||||
ret=$?
|
||||
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null
|
||||
exit $ret
|
||||
' 0
|
||||
|
||||
# Because "mkdir -p" follows existing symlinks and we likely work
|
||||
# directly in world-writeable /tmp, make sure that the '$tmpdir'
|
||||
# directory is successfully created first before we actually test
|
||||
# 'mkdir -p'.
|
||||
if (umask $mkdir_umask &&
|
||||
$mkdirprog $mkdir_mode "$tmpdir" &&
|
||||
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
|
||||
then
|
||||
if test -z "$dir_arg" || {
|
||||
# Check for POSIX incompatibilities with -m.
|
||||
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
|
||||
# other-writable bit of parent directory when it shouldn't.
|
||||
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
|
||||
test_tmpdir="$tmpdir/a"
|
||||
ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
|
||||
case $ls_ld_tmpdir in
|
||||
d????-?r-*) different_mode=700;;
|
||||
d????-?--*) different_mode=755;;
|
||||
*) false;;
|
||||
esac &&
|
||||
$mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
|
||||
ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
|
||||
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
|
||||
}
|
||||
}
|
||||
then posix_mkdir=:
|
||||
fi
|
||||
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
|
||||
else
|
||||
# Remove any dirs left behind by ancient mkdir implementations.
|
||||
rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
|
||||
fi
|
||||
trap '' 0;;
|
||||
esac
|
||||
|
||||
if
|
||||
$posix_mkdir && (
|
||||
umask $mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
|
||||
)
|
||||
then :
|
||||
else
|
||||
|
||||
# mkdir does not conform to POSIX,
|
||||
# or it failed possibly due to a race condition. Create the
|
||||
# directory the slow way, step by step, checking for races as we go.
|
||||
|
||||
case $dstdir in
|
||||
/*) prefix='/';;
|
||||
[-=\(\)!]*) prefix='./';;
|
||||
*) prefix='';;
|
||||
esac
|
||||
|
||||
oIFS=$IFS
|
||||
IFS=/
|
||||
set -f
|
||||
set fnord $dstdir
|
||||
shift
|
||||
set +f
|
||||
IFS=$oIFS
|
||||
|
||||
prefixes=
|
||||
|
||||
for d
|
||||
do
|
||||
test X"$d" = X && continue
|
||||
|
||||
prefix=$prefix$d
|
||||
if test -d "$prefix"; then
|
||||
prefixes=
|
||||
else
|
||||
if $posix_mkdir; then
|
||||
(umask $mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
|
||||
# Don't fail if two instances are running concurrently.
|
||||
test -d "$prefix" || exit 1
|
||||
else
|
||||
case $prefix in
|
||||
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
|
||||
*) qprefix=$prefix;;
|
||||
esac
|
||||
prefixes="$prefixes '$qprefix'"
|
||||
fi
|
||||
fi
|
||||
prefix=$prefix/
|
||||
done
|
||||
|
||||
if test -n "$prefixes"; then
|
||||
# Don't fail if two instances are running concurrently.
|
||||
(umask $mkdir_umask &&
|
||||
eval "\$doit_exec \$mkdirprog $prefixes") ||
|
||||
test -d "$dstdir" || exit 1
|
||||
obsolete_mkdir_used=true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
|
||||
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
|
||||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
|
||||
else
|
||||
|
||||
# Make a couple of temp file names in the proper directory.
|
||||
dsttmp=${dstdirslash}_inst.$$_
|
||||
rmtmp=${dstdirslash}_rm.$$_
|
||||
|
||||
# Trap to clean up those temp files at exit.
|
||||
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
|
||||
|
||||
# Copy the file name to the temp name.
|
||||
(umask $cp_umask &&
|
||||
{ test -z "$stripcmd" || {
|
||||
# Create $dsttmp read-write so that cp doesn't create it read-only,
|
||||
# which would cause strip to fail.
|
||||
if test -z "$doit"; then
|
||||
: >"$dsttmp" # No need to fork-exec 'touch'.
|
||||
else
|
||||
$doit touch "$dsttmp"
|
||||
fi
|
||||
}
|
||||
} &&
|
||||
$doit_exec $cpprog "$src" "$dsttmp") &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits.
|
||||
#
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $cpprog $src $dsttmp" command.
|
||||
#
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
|
||||
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
|
||||
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
|
||||
|
||||
# If -C, don't bother to copy if it wouldn't change the file.
|
||||
if $copy_on_change &&
|
||||
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
|
||||
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
|
||||
set -f &&
|
||||
set X $old && old=:$2:$4:$5:$6 &&
|
||||
set X $new && new=:$2:$4:$5:$6 &&
|
||||
set +f &&
|
||||
test "$old" = "$new" &&
|
||||
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
|
||||
then
|
||||
rm -f "$dsttmp"
|
||||
else
|
||||
# If $backupsuffix is set, and the file being installed
|
||||
# already exists, attempt a backup. Don't worry if it fails,
|
||||
# e.g., if mv doesn't support -f.
|
||||
if test -n "$backupsuffix" && test -f "$dst"; then
|
||||
$doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null
|
||||
fi
|
||||
|
||||
# Rename the file to the real destination.
|
||||
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
|
||||
|
||||
# The rename failed, perhaps because mv can't rename something else
|
||||
# to itself, or perhaps because mv is so ancient that it does not
|
||||
# support -f.
|
||||
{
|
||||
# Now remove or move aside any old file at destination location.
|
||||
# We try this two ways since rm can't unlink itself on some
|
||||
# systems and the destination file might be busy for other
|
||||
# reasons. In this case, the final cleanup might fail but the new
|
||||
# file should still install successfully.
|
||||
{
|
||||
test ! -f "$dst" ||
|
||||
$doit $rmcmd "$dst" 2>/dev/null ||
|
||||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
|
||||
{ $doit $rmcmd "$rmtmp" 2>/dev/null; :; }
|
||||
} ||
|
||||
{ echo "$0: cannot unlink or rename $dst" >&2
|
||||
(exit 1); exit 1
|
||||
}
|
||||
} &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
$doit $mvcmd "$dsttmp" "$dst"
|
||||
}
|
||||
fi || exit 1
|
||||
|
||||
trap '' 0
|
||||
fi
|
||||
done
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'before-save-hook 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC0"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
187
exec/loader-aarch64.s
Normal file
187
exec/loader-aarch64.s
Normal file
|
@ -0,0 +1,187 @@
|
|||
// Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of GNU Emacs.
|
||||
//
|
||||
// GNU Emacs is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// GNU Emacs is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
// Notice that aarch64 requires that sp be aligned to 16 bytes while
|
||||
// accessing memory from sp, so x20 is used to chase down the load
|
||||
// area.
|
||||
|
||||
.section .text
|
||||
.global _start
|
||||
_start:
|
||||
//mov x8, 101 // SYS_nanosleep
|
||||
//adr x0, timespec // req
|
||||
//mov x1, #0 // rem
|
||||
//svc #0 // syscall
|
||||
mov x20, sp // x20 = sp
|
||||
ldr x10, [x20] // x10 = original SP
|
||||
add x20, x20, #16 // x20 = start of load area
|
||||
mov x28, #-1 // x28 = secondary fd
|
||||
.next_action:
|
||||
ldr x11, [x20] // action number
|
||||
and x12, x11, #-17 // actual action number
|
||||
cbz x12, .open_file // open file?
|
||||
cmp x12, #3 // jump?
|
||||
beq .rest_of_exec
|
||||
cmp x12, #4 // anonymous mmap?
|
||||
beq .do_mmap_anon
|
||||
.do_mmap:
|
||||
ldr x0, [x20, 8] // vm_address
|
||||
ldr x1, [x20, 32] // length
|
||||
ldr x2, [x20, 24] // protection
|
||||
ldr x3, [x20, 40] // flags
|
||||
tst x11, #16 // primary fd?
|
||||
mov x4, x29 // primary fd
|
||||
beq .do_mmap_1
|
||||
mov x4, x28 // secondary fd
|
||||
.do_mmap_1:
|
||||
mov x8, #222 // SYS_mmap
|
||||
ldr x5, [x20, 16] // file_offset
|
||||
svc #0 // syscall
|
||||
ldr x9, [x20, 8] // length
|
||||
cmp x0, x9 // mmap result
|
||||
bne .perror // print error
|
||||
ldr x3, [x20, 48] // clear
|
||||
add x1, x1, x0 // x1 = vm_address + end
|
||||
sub x3, x1, x3 // x3 = x1 - clear
|
||||
mov x0, #0 // x0 = 0
|
||||
.fill64:
|
||||
sub x2, x1, x3 // x2 = x1 - x3
|
||||
cmp x2, #63 // x2 >= 64?
|
||||
ble .fillb // start filling bytes
|
||||
stp x0, x0, [x3] // x3[0] = 0, x3[1] = 0
|
||||
stp x0, x0, [x3, 16] // x3[2] = 0, x3[3] = 0
|
||||
stp x0, x0, [x3, 32] // x3[4] = 0, x3[5] = 0
|
||||
stp x0, x0, [x3, 48] // x3[6] = 0, x3[7] = 0
|
||||
add x3, x3, #64 // x3 += 8
|
||||
b .fill64
|
||||
.fillb:
|
||||
cmp x1, x3 // x1 == x3?
|
||||
beq .continue // done
|
||||
strb w0, [x3], #1 // ((char *) x3)++ = 0
|
||||
b .fillb
|
||||
.continue:
|
||||
add x20, x20, #56 // next action
|
||||
b .next_action
|
||||
.do_mmap_anon:
|
||||
ldr x0, [x20, 8] // vm_address
|
||||
ldr x1, [x20, 32] // length
|
||||
ldr x2, [x20, 24] // protection
|
||||
ldr x3, [x20, 40] // flags
|
||||
mov x4, #-1 // fd
|
||||
b .do_mmap_1
|
||||
.open_file:
|
||||
mov x8, #56 // SYS_openat
|
||||
mov x0, #-100 // AT_FDCWD
|
||||
add x1, x20, #8 // file name
|
||||
mov x2, #0 // O_RDONLY
|
||||
mov x3, #0 // mode
|
||||
svc #0 // syscall
|
||||
cmp x0, #-1 // rc < 0?
|
||||
ble .perror
|
||||
mov x19, x1 // x19 == x1
|
||||
.nextc:
|
||||
ldrb w2, [x1], #1 // b = *x1++
|
||||
cmp w2, #47 // dir separator?
|
||||
bne .nextc1 // not dir separator
|
||||
mov x19, x1 // x19 = char past separator
|
||||
.nextc1:
|
||||
cbnz w2, .nextc // b?
|
||||
add x1, x1, #7 // round up x1
|
||||
and x20, x1, #-8 // mask for round, set x20
|
||||
tst x11, #16 // primary fd?
|
||||
bne .secondary // secondary fd
|
||||
mov x29, x0 // primary fd
|
||||
mov x8, #167 // SYS_prctl
|
||||
mov x0, #15 // PR_SET_NAME
|
||||
mov x1, x19 // basename
|
||||
mov x2, #0 // arg2
|
||||
mov x3, #0 // arg3
|
||||
mov x4, #0 // arg4
|
||||
mov x5, #0 // arg5
|
||||
svc #0 // syscall
|
||||
b .next_action // next action
|
||||
.secondary:
|
||||
mov x28, x0 // secondary fd
|
||||
b .next_action // next action.
|
||||
.perror:
|
||||
mov x8, #93 // SYS_exit
|
||||
mvn x0, x0 // x1 = ~x0
|
||||
add x0, x0, 1 // x1 += 1
|
||||
svc #0 // exit
|
||||
.rest_of_exec:
|
||||
mov x7, x20 // x7 = x20
|
||||
mov x20, x10 // x20 = x10
|
||||
ldr x9, [x20] // argc
|
||||
add x9, x9, #2 // x9 += 2
|
||||
lsl x9, x9, #3 // argc * 8
|
||||
add x20, x20, x9 // now past argv
|
||||
.skipenv:
|
||||
ldr x9, [x20], #8 // x9 = *envp++
|
||||
cbnz x9, .skipenv // x9?
|
||||
.one_auxv:
|
||||
ldr x9, [x20], #16 // x9 = *sp, sp += 2
|
||||
cbz x9, .cleanup // !x9?
|
||||
cmp x9, #3 // is AT_PHDR?
|
||||
beq .replace_phdr // replace
|
||||
cmp x9, #4 // is AT_PHENT?
|
||||
beq .replace_phent // replace
|
||||
cmp x9, #5 // is AT_PHNUM?
|
||||
beq .replace_phnum // replace
|
||||
cmp x9, #9 // is AT_ENTRY?
|
||||
beq .replace_entry // replace
|
||||
cmp x9, #7 // is AT_BASE?
|
||||
beq .replace_base // replace
|
||||
b .one_auxv // next auxv
|
||||
.replace_phdr:
|
||||
ldr x9, [x7, 40] // at_phdr
|
||||
str x9, [x20, -8] // store value
|
||||
b .one_auxv
|
||||
.replace_phent:
|
||||
ldr x9, [x7, 24] // at_phent
|
||||
str x9, [x20, -8] // store value
|
||||
b .one_auxv
|
||||
.replace_phnum:
|
||||
ldr x9, [x7, 32] // at_phnum
|
||||
str x9, [x20, -8] // store value
|
||||
b .one_auxv
|
||||
.replace_entry:
|
||||
ldr x9, [x7, 16] // at_entry
|
||||
str x9, [x20, -8] // store value
|
||||
b .one_auxv
|
||||
.replace_base:
|
||||
ldr x9, [x7, 48] // at_base
|
||||
str x9, [x20, -8] // store value
|
||||
b .one_auxv
|
||||
.cleanup:
|
||||
cmp x28, #-1 // is secondary fd set?
|
||||
bne .cleanup1 // not set
|
||||
mov x8, #57 // SYS_close
|
||||
mov x0, x28 // secondary fd
|
||||
svc #0 // syscall
|
||||
.cleanup1:
|
||||
mov x8, #57 // SYS_close
|
||||
mov x0, x29 // primary fd
|
||||
svc #0 // syscall
|
||||
.enter:
|
||||
mov sp, x10 // restore original SP
|
||||
mov x0, #0 // clear rtld_fini
|
||||
ldr x1, [x7, 8] // branch to code
|
||||
br x1
|
||||
|
||||
timespec:
|
||||
.quad 10
|
||||
.quad 10
|
204
exec/loader-armeabi.s
Normal file
204
exec/loader-armeabi.s
Normal file
|
@ -0,0 +1,204 @@
|
|||
@ Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
@
|
||||
@ This file is part of GNU Emacs.
|
||||
@
|
||||
@ GNU Emacs is free software: you can redistribute it and/or modify
|
||||
@ it under the terms of the GNU General Public License as published
|
||||
@ by the Free Software Foundation, either version 3 of the License,
|
||||
@ or (at your option) any later version.
|
||||
@
|
||||
@ GNU Emacs is distributed in the hope that it will be useful, but
|
||||
@ WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
@ General Public License for more details.
|
||||
@
|
||||
@ You should have received a copy of the GNU General Public License
|
||||
@ along with GNU Emacs. If not, see <https:@www.gnu.org/licenses/>.
|
||||
|
||||
.section .text
|
||||
.global _start
|
||||
_start:
|
||||
@mov r7, #162 @ SYS_nanosleep
|
||||
@adr r0, timespec @ req
|
||||
@mov r1, #0 @ rem
|
||||
@swi #0 @ syscall
|
||||
mov r8, sp @ r8 = sp
|
||||
ldr r9, [r8], #8 @ r9 = original sp, r8 += 8
|
||||
mov r14, #-1 @ r14 = secondary fd
|
||||
.next_action:
|
||||
ldr r11, [r8] @ r11 = action number
|
||||
and r12, r11, #-17 @ actual action number
|
||||
cmp r12, #0 @ open file?
|
||||
beq .open_file @ open file.
|
||||
cmp r12, #3 @ jump?
|
||||
beq .rest_of_exec @ jump to code.
|
||||
cmp r12, #4 @ anonymous mmap?
|
||||
beq .do_mmap_anon @ anonymous mmap.
|
||||
.do_mmap:
|
||||
add r6, r8, #4 @ r6 = r8 + 4
|
||||
ldm r6!, {r0, r5} @ vm_address, file_offset
|
||||
ldm r6!, {r1, r2} @ protection, length
|
||||
mov r3, r1 @ swap
|
||||
lsr r5, #12 @ divide file offset by page size
|
||||
mov r1, r2 @ swap
|
||||
mov r2, r3 @ swap
|
||||
ldm r6!, {r3, r12} @ flags, clear
|
||||
tst r11, #16 @ primary fd?
|
||||
mov r4, r10 @ primary fd
|
||||
beq .do_mmap_1
|
||||
mov r4, r14 @ secondary fd
|
||||
.do_mmap_1:
|
||||
mov r7, #192 @ SYS_mmap2
|
||||
swi #0 @ syscall
|
||||
ldr r2, [r8, #4] @ vm_address
|
||||
cmp r2, r0 @ rc == vm_address?
|
||||
bne .perror
|
||||
add r0, r1, r2 @ r0 = length + vm_address
|
||||
sub r3, r0, r12 @ r3 = r0 - clear
|
||||
mov r1, #0 @ r1 = 0
|
||||
.align:
|
||||
cmp r0, r3 @ r0 == r3?
|
||||
beq .continue @ continue
|
||||
tst r3, #3 @ r3 & 3?
|
||||
bne .fill32 @ fill aligned
|
||||
strb r1, [r3], #1 @ fill byte
|
||||
b .align @ align again
|
||||
.fill32:
|
||||
sub r2, r0, r3 @ r2 = r0 - r3
|
||||
cmp r2, #31 @ r2 >= 32?
|
||||
ble .fillb @ start filling bytes
|
||||
str r1, [r3], #4 @ *r3++ = 0
|
||||
str r1, [r3], #4 @ *r3++ = 0
|
||||
str r1, [r3], #4 @ *r3++ = 0
|
||||
str r1, [r3], #4 @ *r3++ = 0
|
||||
str r1, [r3], #4 @ *r3++ = 0
|
||||
str r1, [r3], #4 @ *r3++ = 0
|
||||
str r1, [r3], #4 @ *r3++ = 0
|
||||
str r1, [r3], #4 @ *r3++ = 0
|
||||
b .fill32
|
||||
.fillb:
|
||||
cmp r0, r3 @ r0 == r3
|
||||
beq .continue @ done
|
||||
strb r1, [r3], #1 @ ((char *) r3)++ = 0
|
||||
b .fillb
|
||||
.continue:
|
||||
add r8, r8, #28 @ next action
|
||||
b .next_action
|
||||
.do_mmap_anon:
|
||||
add r6, r8, #4 @ r6 = r8 + 4
|
||||
ldm r6!, {r0, r5} @ vm_address, file_offset
|
||||
ldm r6!, {r1, r2} @ protection, length
|
||||
mov r3, r1 @ swap
|
||||
lsr r5, #12 @ divide file offset by page size
|
||||
mov r1, r2 @ swap
|
||||
mov r2, r3 @ swap
|
||||
ldm r6!, {r3, r12} @ flags, clear
|
||||
mov r4, #-1 @ fd
|
||||
b .do_mmap_1
|
||||
.open_file:
|
||||
mov r7, #5 @ SYS_open
|
||||
add r0, r8, #4 @ file name
|
||||
mov r1, #0 @ O_RDONLY
|
||||
mov r2, #0 @ mode
|
||||
swi #0 @ syscall
|
||||
cmp r0, #-1 @ r0 <= -1?
|
||||
ble .perror
|
||||
add r8, r8, #4 @ r8 = start of string
|
||||
mov r1, r8 @ r1 = r8
|
||||
.nextc:
|
||||
ldrb r2, [r8], #1 @ b = *r0++
|
||||
cmp r2, #47 @ dir separator?
|
||||
bne .nextc1 @ not dir separator
|
||||
mov r1, r8 @ r1 = char past separator
|
||||
.nextc1:
|
||||
cmp r2, #0 @ b?
|
||||
bne .nextc @ next character
|
||||
add r8, r8, #3 @ round up r8
|
||||
and r8, r8, #-4 @ mask for round, set r8
|
||||
tst r11, #16 @ primary fd?
|
||||
bne .secondary @ secondary fd
|
||||
mov r10, r0 @ primary fd
|
||||
mov r7, #172 @ SYS_prctl
|
||||
mov r0, #15 @ PR_SET_NAME, r1 = name
|
||||
mov r2, #0 @ arg2
|
||||
mov r3, #0 @ arg3
|
||||
mov r4, #0 @ arg4
|
||||
mov r5, #0 @ arg5
|
||||
swi #0 @ syscall
|
||||
b .next_action @ next action
|
||||
.secondary:
|
||||
mov r14, r0 @ secondary fd
|
||||
b .next_action @ next action
|
||||
.perror:
|
||||
mov r7, #1 @ SYS_exit
|
||||
mvn r0, r0 @ r0 = ~r0
|
||||
add r0, r0, #1 @ r0 += 1
|
||||
swi #0
|
||||
.rest_of_exec:
|
||||
mov r7, r9 @ r7 = original SP
|
||||
ldr r6, [r7] @ argc
|
||||
add r6, r6, #2 @ argc + 2
|
||||
lsl r6, r6, #2 @ argc *= 4
|
||||
add r7, r7, r6 @ now past argv
|
||||
.skipenv:
|
||||
ldr r6, [r7], #4 @ r6 = *r7++
|
||||
cmp r6, #0 @ r6?
|
||||
bne .skipenv @ r6?
|
||||
.one_auxv:
|
||||
ldr r6, [r7], #8 @ r6 = *r7, r7 += 2
|
||||
cmp r6, #0 @ !r6?
|
||||
beq .cleanup @ r6?
|
||||
cmp r6, #3 @ is AT_PHDR?
|
||||
beq .replace_phdr @ replace
|
||||
cmp r6, #4 @ is AT_PHENT?
|
||||
beq .replace_phent @ replace
|
||||
cmp r6, #5 @ is AT_PHNUM?
|
||||
beq .replace_phnum @ replace
|
||||
cmp r6, #9 @ is AT_ENTRY?
|
||||
beq .replace_entry @ replace
|
||||
cmp r6, #7 @ is AT_BASE?
|
||||
beq .replace_base @ replace
|
||||
b .one_auxv @ next auxv
|
||||
.replace_phdr:
|
||||
ldr r6, [r8, #20] @ at_phdr
|
||||
str r6, [r7, #-4] @ store value
|
||||
b .one_auxv
|
||||
.replace_phent:
|
||||
ldr r6, [r8, #12] @ at_phent
|
||||
str r6, [r7, #-4] @ store value
|
||||
b .one_auxv
|
||||
.replace_phnum:
|
||||
ldr r6, [r8, #16] @ at_phnum
|
||||
str r6, [r7, #-4] @ store value
|
||||
b .one_auxv
|
||||
.replace_entry:
|
||||
ldr r6, [r8, #8] @ at_entry
|
||||
str r6, [r7, #-4] @ store value
|
||||
b .one_auxv
|
||||
.replace_base:
|
||||
ldr r6, [r8, #24] @ at_base
|
||||
str r6, [r7, #-4] @ store value
|
||||
b .one_auxv
|
||||
.cleanup:
|
||||
cmp r14, #-1 @ secondary fd set?
|
||||
bne .cleanup1 @ not set
|
||||
mov r7, #6 @ SYS_close
|
||||
mov r0, r14 @ secondary fd
|
||||
swi #0 @ syscall
|
||||
.cleanup1:
|
||||
mov r7, #6 @ SYS_close
|
||||
mov r0, r10 @ primary fd
|
||||
swi #0 @ syscall
|
||||
.enter:
|
||||
mov sp, r9 @ restore original SP
|
||||
mov r0, #0 @ clear rtld_fini
|
||||
ldr r1, [r8, #4] @ branch to code
|
||||
bx r1
|
||||
|
||||
timespec:
|
||||
.long 10
|
||||
.long 10
|
||||
|
||||
@ Local Variables:
|
||||
@ asm-comment-char: 64
|
||||
@ End:
|
234
exec/loader-mips64el.s
Normal file
234
exec/loader-mips64el.s
Normal file
|
@ -0,0 +1,234 @@
|
|||
# Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Emacs.
|
||||
#
|
||||
# GNU Emacs is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License,
|
||||
# or (at your option) any later version.
|
||||
#
|
||||
# GNU Emacs is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
include(`config-mips.m4')
|
||||
|
||||
.set noreorder # delay slots managed by hand
|
||||
.set noat # no assembler macros
|
||||
.section .text
|
||||
.global __start
|
||||
__start:
|
||||
dnl li $v0, 5034 # SYS_nanosleep
|
||||
dnl dla $a0, .timespec # rqtp
|
||||
dnl li $a1, 0 # rmtp
|
||||
dnl syscall # syscall
|
||||
ld $s2, ($sp) # original stack pointer
|
||||
DADDI3( $s0, $sp, 16) # start of load area
|
||||
DADDI2( $sp, -16) # primary fd, secondary fd
|
||||
li $t0, -1 # secondary fd
|
||||
sd $t0, 8($sp) # initialize secondary fd
|
||||
.next_action:
|
||||
ld $s1, ($s0) # action number
|
||||
andi $t0, $s1, 15 # t0 = action number & 15
|
||||
beqz $t0, .open_file # open file?
|
||||
nop # delay slot
|
||||
DADDI2( $t0, -3) # t0 -= 3
|
||||
beqz $t0, .rest_of_exec # jump to code
|
||||
nop # delay slot
|
||||
li $t1, 1
|
||||
beq $t0, $t1, .do_mmap_anon # anonymous mmap?
|
||||
nop # delay slot
|
||||
.do_mmap:
|
||||
ld $t0, 8($s0) # vm address
|
||||
ld $t1, 16($s0) # file_offset
|
||||
ld $t2, 24($s0) # protection
|
||||
ld $t3, 32($s0) # length
|
||||
ld $v0, 40($s0) # flags
|
||||
ld $v1, ($sp) # primary fd
|
||||
andi $s3, $s1, 16 # s1 & 16?
|
||||
beqz $s3, .do_mmap_1 # secondary fd?
|
||||
nop # delay slot
|
||||
ld $v1, 8($sp) # secondary fd
|
||||
.do_mmap_1:
|
||||
move $a0, $t0 # syscall arg
|
||||
move $a1, $t3 # syscall arg
|
||||
move $a2, $t2 # syscall arg
|
||||
move $a3, $v0 # syscall arg
|
||||
move $a4, $v1 # syscall arg
|
||||
move $a5, $t1 # syscall arg
|
||||
li $v0, 5009 # SYS_mmap
|
||||
syscall # syscall
|
||||
bne $a3, $zero, .perror # perror?
|
||||
nop # delay slot
|
||||
ld $t1, 48($s0) # clear
|
||||
dadd $t0, $a0, $a1 # t0 = end of mapping
|
||||
dsub $t1, $t0, $t1 # t1 = t0 - clear
|
||||
.align:
|
||||
beq $t0, $t1, .continue # already finished
|
||||
nop # delay slot
|
||||
andi $t2, $t1, 7 # t1 & 7?
|
||||
bnez $t2, .filld # start filling longs
|
||||
nop # delay slot
|
||||
.filld:
|
||||
dsub $t2, $t0, $t1 # t2 = t0 - t1
|
||||
sltiu $t2, $t2, 64 # t2 < 64?
|
||||
bne $t2, $zero, .fillb # fill bytes
|
||||
nop # delay slot
|
||||
sd $zero, ($t1) # zero doubleword
|
||||
DADDI2( $t1, 8) # next doubleword
|
||||
sd $zero, ($t1) # zero doubleword
|
||||
DADDI2( $t1, 8) # next doubleword
|
||||
sd $zero, ($t1) # zero doubleword
|
||||
DADDI2( $t1, 8) # next doubleword
|
||||
sd $zero, ($t1) # zero doubleword
|
||||
DADDI2( $t1, 8) # next doubleword
|
||||
sd $zero, ($t1) # zero doubleword
|
||||
DADDI2( $t1, 8) # next doubleword
|
||||
sd $zero, ($t1) # zero doubleword
|
||||
DADDI2( $t1, 8) # next doubleword
|
||||
sd $zero, ($t1) # zero doubleword
|
||||
DADDI2( $t1, 8) # next doubleword
|
||||
sd $zero, ($t1) # zero doubleword
|
||||
DADDI2( $t1, 8) # next doubleword
|
||||
j .filld # fill either doubleword or byte
|
||||
nop # delay slot
|
||||
.fillb:
|
||||
beq $t0, $t1, .continue # already finished?
|
||||
nop # delay slot
|
||||
sb $zero, ($t1) # clear byte
|
||||
DADDI2( $t1, 1) # t1++
|
||||
.continue:
|
||||
DADDI2( $s0, 56) # s0 = next action
|
||||
j .next_action # next action
|
||||
nop # delay slot
|
||||
.do_mmap_anon:
|
||||
ld $t0, 8($s0) # vm address
|
||||
ld $t1, 16($s0) # file_offset
|
||||
ld $t2, 24($s0) # protection
|
||||
ld $t3, 32($s0) # length
|
||||
ld $v0, 40($s0) # flags
|
||||
li $v1, -1 # fd
|
||||
j .do_mmap_1 # do mmap
|
||||
nop # branch delay slot
|
||||
.open_file:
|
||||
li $v0, 5002 # SYS_open
|
||||
DADDI3( $a0, $s0, 8) # start of name
|
||||
move $a1, $zero # flags = O_RDONLY
|
||||
move $a2, $zero # mode = 0
|
||||
syscall # syscall
|
||||
bne $a3, $zero, .perror # perror
|
||||
nop # delay slot
|
||||
DADDI2( $s0, 8) # start of string
|
||||
move $t3, $s0 # t3 = s0
|
||||
.nextc:
|
||||
lb $t0, ($s0) # load byte
|
||||
DADDI2( $s0, 1) # s0++
|
||||
li $t1, 47 # directory separator `/'
|
||||
bne $t0, $t1, .nextc1 # is separator char?
|
||||
nop # delay slot
|
||||
move $t3, $s0 # t3 = char past separator
|
||||
.nextc1:
|
||||
bnez $t0, .nextc # next character?
|
||||
nop # delay slot
|
||||
DADDI2( $s0, 7) # adjust for round
|
||||
li $t2, -8 # t2 = -8
|
||||
and $s0, $s0, $t2 # mask for round
|
||||
andi $t0, $s1, 16 # t1 = s1 & 16
|
||||
move $t1, $sp # address of primary fd
|
||||
beqz $t0, .primary # primary fd?
|
||||
nop # delay slot
|
||||
DADDI2( $t1, 8) # address of secondary fd
|
||||
sd $v0, ($t1) # store fd
|
||||
j .next_action # next action
|
||||
nop # delay slot
|
||||
.primary:
|
||||
sd $v0, ($t1) # store fd
|
||||
li $v0, 5153 # SYS_prctl
|
||||
li $a0, 15 # PR_SET_NAME
|
||||
move $a1, $t3 # char past separator
|
||||
move $a2, $zero # a2
|
||||
move $a3, $zero # a3
|
||||
move $a4, $zero # a4
|
||||
move $a5, $zero # a5
|
||||
syscall # syscall
|
||||
j .next_action # next action
|
||||
nop # delay slot
|
||||
.perror:
|
||||
move $a0, $v0 # errno
|
||||
li $v0, 5058 # SYS_exit
|
||||
syscall # syscall
|
||||
.rest_of_exec:
|
||||
move $s1, $s2 # original SP
|
||||
ld $t0, ($s1) # argc
|
||||
dsll $t0, $t0, 3 # argc *= 8
|
||||
DADDI2( $t0, 16) # argc += 16
|
||||
dadd $s1, $s1, $t0 # s1 = start of envp
|
||||
.skipenv:
|
||||
ld $t0, ($s1) # t0 = *s1
|
||||
DADDI2( $s1, 8) # s1++
|
||||
bne $t0, $zero, .skipenv # skip again
|
||||
nop # delay slot
|
||||
dla $t3, .auxvtab # address of auxv table
|
||||
.one_auxv:
|
||||
ld $t0, ($s1) # t0 = auxv type
|
||||
li $t1, 10 # t1 = 10
|
||||
beqz $t0, .finish # is AT_IGNORE?
|
||||
nop # delay slot
|
||||
sltu $t1, $t0, $t1 # t1 = t0 < num offsets
|
||||
beqz $t1, .next # next auxv
|
||||
nop # delay slot
|
||||
dsll $t1, $t0, 2 # t1 = t0 * 4
|
||||
dadd $t1, $t3, $t1 # t1 = .auxvtab + t1
|
||||
lw $t2, ($t1) # t2 = *t1
|
||||
beqz $t2, .next # skip auxv
|
||||
nop # delay slot
|
||||
dadd $t2, $s0, $t2 # t2 = s0 + t2
|
||||
ld $t2, ($t2) # t2 = *t2
|
||||
sd $t2, 8($s1) # set auxv value
|
||||
.next:
|
||||
DADDI2( $s1, 16) # next auxv
|
||||
j .one_auxv # next auxv
|
||||
nop # delay slot
|
||||
.finish:
|
||||
ld $t0, 8($sp) # secondary fd
|
||||
li $t1, -1 # t1 = -1
|
||||
ld $s1, ($sp) # s1 = primary fd
|
||||
li $v0, 5003 # SYS_close
|
||||
beq $t0, $t2, .finish1 # secondary fd set?
|
||||
nop # delay slot
|
||||
move $a0, $t0 # secondary fd
|
||||
syscall # syscall
|
||||
li $v0, 5003 # SYS_close
|
||||
.finish1:
|
||||
move $a0, $s1 # primary fd
|
||||
syscall # syscall
|
||||
.jump:
|
||||
move $v0, $zero # rtld_fini
|
||||
ld $t0, 8($s0) # entry
|
||||
move $sp, $s2 # restore stack pointer, delay slot
|
||||
jr $t0 # enter
|
||||
nop # delay slot
|
||||
|
||||
.auxvtab:
|
||||
.long 0 # 0
|
||||
.long 0 # 1
|
||||
.long 0 # 2
|
||||
.long 40 # 3 AT_PHDR
|
||||
.long 24 # 4 AT_PHENT
|
||||
.long 32 # 5 AT_PHNUM
|
||||
.long 0 # 6
|
||||
.long 48 # 7 AT_BASE
|
||||
.long 0 # 8
|
||||
.long 16 # 9 AT_ENTRY
|
||||
|
||||
.timespec:
|
||||
.quad 10
|
||||
.quad 10
|
||||
|
||||
# Local Variables:
|
||||
# asm-comment-char: 35
|
||||
# End:
|
236
exec/loader-mipsel.s
Normal file
236
exec/loader-mipsel.s
Normal file
|
@ -0,0 +1,236 @@
|
|||
# Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Emacs.
|
||||
#
|
||||
# GNU Emacs is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License,
|
||||
# or (at your option) any later version.
|
||||
#
|
||||
# GNU Emacs is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
include(`config-mips.m4')
|
||||
|
||||
# Make sure not to use t4 through t7, in order to maintain portability
|
||||
# with N32 ABI systems.
|
||||
|
||||
.set noreorder # delay slots managed by hand
|
||||
.section .text
|
||||
.global __start
|
||||
__start:
|
||||
dnl li $v0, SYSCALL_nanosleep # SYS_nanosleep
|
||||
dnl la $a0, .timespec # rqtp
|
||||
dnl li $a1, 0 # rmtp
|
||||
dnl syscall # syscall
|
||||
lw $s6, ($sp) # original stack pointer
|
||||
addi $s0, $sp, 8 # start of load area
|
||||
addi $sp, -8 # primary fd, secondary fd
|
||||
li $t0, -1 # secondary fd
|
||||
sw $t0, 4($sp) # initialize secondary fd
|
||||
.next_action:
|
||||
lw $s2, ($s0) # action number
|
||||
nop # delay slot
|
||||
andi $t0, $s2, 15 # t0 = s2 & 15
|
||||
beqz $t0, .open_file # open file?
|
||||
li $t1, 3 # t1 = 3, delay slot
|
||||
beq $t0, $t1, .rest_of_exec # jump to code
|
||||
li $t1, 4 # t1 = 4, delay slot
|
||||
beq $t0, $t1, .do_mmap_anon # anonymous mmap
|
||||
.do_mmap:
|
||||
lw $a0, 4($s0) # vm_address, delay slot
|
||||
lw $v1, 8($s0) # file_offset
|
||||
lw $a2, 12($s0) # protection
|
||||
lw $a1, 16($s0) # length
|
||||
lw $a3, 20($s0) # flags
|
||||
lw $v0, ($sp) # primary fd
|
||||
andi $t1, $s2, 16 # t1 = s2 & 16
|
||||
beqz $t1, .do_mmap_1 # secondary fd?
|
||||
nop # delay slot
|
||||
lw $v0, 4($sp) # secondary fd
|
||||
nop # delay slot
|
||||
.do_mmap_1:
|
||||
SYSCALL(`$v0',`$v1',`$zero',`$zero') # syscall args
|
||||
li $v0, SYSCALL_mmap # SYS_mmap
|
||||
syscall # syscall
|
||||
bne $a3, $zero, .perror # perror
|
||||
RESTORE() # delay slot, restore sp
|
||||
lw $s5, 24($s0) # clear
|
||||
add $t0, $a0, $a1 # t0 = length + vm_address, delay slot
|
||||
sub $t1, $t0, $s5 # t1 = t0 - clear
|
||||
.align:
|
||||
beq $t0, $t1, .continue # already finished?
|
||||
nop # delay slot
|
||||
andi $t2, $t1, 3 # t1 & 3?
|
||||
bnez $t2, .fillw # start filling longs
|
||||
nop # delay slot
|
||||
sb $zero, ($t1) # clear byte
|
||||
addi $t1, $t1, 1 # t1++
|
||||
j .align # continue
|
||||
nop # delay slot
|
||||
.fillw:
|
||||
sub $t2, $t0, $t1 # t2 = t0 - t1
|
||||
sltiu $t2, $t2, 32 # r2 < 32?
|
||||
bne $t2, $zero, .fillb # fill bytes
|
||||
nop # delay slot
|
||||
sw $zero, ($t1) # zero word
|
||||
addi $t1, $t1, 4 # next word
|
||||
sw $zero, ($t1) # zero word
|
||||
addi $t1, $t1, 4 # next word
|
||||
sw $zero, ($t1) # zero word
|
||||
addi $t1, $t1, 4 # next word
|
||||
sw $zero, ($t1) # zero word
|
||||
addi $t1, $t1, 4 # next word
|
||||
sw $zero, ($t1) # zero word
|
||||
addi $t1, $t1, 4 # next word
|
||||
sw $zero, ($t1) # zero word
|
||||
addi $t1, $t1, 4 # next word
|
||||
sw $zero, ($t1) # zero word
|
||||
addi $t1, $t1, 4 # next word
|
||||
sw $zero, ($t1) # zero word
|
||||
addi $t1, $t1, 4 # next word
|
||||
j .fillw # fill either word or byte
|
||||
nop # delay slot
|
||||
.fillb:
|
||||
beq $t0, $t1, .continue # already finished?
|
||||
nop # delay slot
|
||||
sb $zero, ($t1) # clear byte
|
||||
addi $t1, $t1, 1 # t1++
|
||||
.continue:
|
||||
addi $s0, $s0, 28 # s0 = next action
|
||||
j .next_action # next action
|
||||
nop # delay slot
|
||||
.do_mmap_anon:
|
||||
lw $v1, 8($s0) # file_offset
|
||||
lw $a2, 12($s0) # protection
|
||||
lw $a1, 16($s0) # length
|
||||
lw $a3, 20($s0) # flags
|
||||
li $t4, -1 # fd
|
||||
j .do_mmap_1 # do mmap
|
||||
nop # delay slot
|
||||
.open_file:
|
||||
li $v0, SYSCALL_open # SYS_open
|
||||
addi $a0, $s0, 4 # start of name
|
||||
move $a1, $zero # flags = O_RDONLY
|
||||
move $a2, $zero # mode = 0
|
||||
syscall # syscall
|
||||
bne $a3, $zero, .perror # perror
|
||||
addi $s0, $s0, 4 # start of string, delay slot
|
||||
move $t3, $s0 # t3 = char past separator
|
||||
.nextc:
|
||||
lb $t0, ($s0) # load byte
|
||||
addi $s0, $s0, 1 # s0++
|
||||
li $t1, 47 # directory separator `/'
|
||||
bne $t0, $t1, .nextc1 # is separator char?
|
||||
nop # delay slot
|
||||
move $t3, $s0 # t3 = char past separator
|
||||
.nextc1:
|
||||
bnez $t0, .nextc # next character?
|
||||
nop # delay slot
|
||||
addi $s0, $s0, 3 # adjust for round
|
||||
li $t2, -4 # t2 = -4
|
||||
and $s0, $s0, $t2 # mask for round
|
||||
andi $t0, $s2, 16 # t1 = s2 & 16
|
||||
beqz $t0, .primary # primary fd?
|
||||
move $t0, $sp # address of primary fd, delay slot
|
||||
addi $t0, $t0, 4 # address of secondary fd
|
||||
j .next_action # next action
|
||||
.primary:
|
||||
sw $v0, ($t0) # store fd, delay slot
|
||||
li $v0, SYSCALL_prctl # SYS_prctl
|
||||
li $a0, 15 # PR_SET_NAME
|
||||
move $a1, $t3 # name
|
||||
move $a2, $zero # arg1
|
||||
move $a3, $zero # arg2
|
||||
SYSCALL(`$a2',`$a2',`$a2',`$a2') # syscall args
|
||||
syscall # syscall
|
||||
RESTORE() # restore sp
|
||||
j .next_action # next action
|
||||
nop # delay slot
|
||||
.perror:
|
||||
move $a0, $v0 # errno
|
||||
li $v0, SYSCALL_exit # SYS_exit
|
||||
syscall # syscall
|
||||
.rest_of_exec:
|
||||
move $s1, $s6 # s1 = original SP
|
||||
lw $t0, ($s1) # argc
|
||||
nop # delay slot
|
||||
sll $t0, $t0, 2 # argc *= 4
|
||||
addi $t0, $t0, 8 # argc += 8
|
||||
add $s1, $s1, $t0 # s1 = start of envp
|
||||
.skipenv:
|
||||
lw $t0, ($s1) # t0 = *s1
|
||||
addi $s1, $s1, 4 # s1++
|
||||
bne $t0, $zero, .skipenv # skip again
|
||||
nop # delay slot
|
||||
la $s2, .auxvtab # address of auxv table
|
||||
.one_auxv:
|
||||
lw $t0, ($s1) # t0 = auxv type
|
||||
li $t1, 10 # t1 = 10, delay slot
|
||||
beqz $t0, .finish # is AT_IGNORE?
|
||||
sltu $t1, $t0, $t1 # t1 = t0 < num offsets, delay slot
|
||||
beq $t1, $zero, .next # next auxv
|
||||
sll $t1, $t0, 2 # t1 = t0 * 4, delay slot
|
||||
add $t1, $s2, $t1 # t1 = .auxvtab + t1
|
||||
lw $t2, ($t1) # t2 = *t1
|
||||
nop # delay slot
|
||||
beqz $t2, .next # skip auxv
|
||||
add $t2, $s0, $t2 # t2 = s0 + t2
|
||||
lw $t2, ($t2) # t2 = *t2
|
||||
nop # delay slot
|
||||
sw $t2, 4($s1) # set auxv value
|
||||
.next:
|
||||
addi $s1, $s1, 8 # next auxv
|
||||
j .one_auxv # next auxv
|
||||
nop # delay slot
|
||||
.finish:
|
||||
lw $t0, 4($sp) # secondary fd
|
||||
lw $s1, ($sp) # primary fd, delay slot, preserved
|
||||
li $t2, -1 # immediate -1
|
||||
beq $t0, $t2, .finish1 # secondary fd set?
|
||||
li $v0, SYSCALL_close # SYS_close, delay slot
|
||||
move $a0, $t0 # fd
|
||||
syscall # syscall
|
||||
li $v0, SYSCALL_close # SYS_close
|
||||
.finish1:
|
||||
move $a0, $s1 # primary fd
|
||||
syscall # syscall
|
||||
li $v0, SYSCALL_prctl # SYS_prctl
|
||||
li $a0, 45 # PR_SET_FP_MODE
|
||||
lw $a1, 28($s0) # fpu_mode
|
||||
move $a2, $zero # arg3
|
||||
move $a3, $zero # arg4
|
||||
SYSCALL(`$a2',`$a2',`$a2',`$a2') # syscall args
|
||||
syscall # syscall
|
||||
RESTORE() # restore sp
|
||||
.jump:
|
||||
move $v0, $zero # rtld_fini
|
||||
lw $t0, 4($s0) # entry
|
||||
move $sp, $s6 # restore stack pointer, delay slot
|
||||
jr $t0 # enter
|
||||
nop # delay slot
|
||||
|
||||
.auxvtab:
|
||||
.long 0 # 0
|
||||
.long 0 # 1
|
||||
.long 0 # 2
|
||||
.long 20 # 3 AT_PHDR
|
||||
.long 12 # 4 AT_PHENT
|
||||
.long 16 # 5 AT_PHNUM
|
||||
.long 0 # 6
|
||||
.long 24 # 7 AT_BASE
|
||||
.long 0 # 8
|
||||
.long 8 # 9 AT_ENTRY
|
||||
|
||||
.timespec:
|
||||
.long 10
|
||||
.long 10
|
||||
|
||||
# Local Variables:
|
||||
# asm-comment-char: 35
|
||||
# End:
|
203
exec/loader-x86.s
Normal file
203
exec/loader-x86.s
Normal file
|
@ -0,0 +1,203 @@
|
|||
define(`CC', `
|
||||
dnl')
|
||||
|
||||
CC Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
CC
|
||||
CC This file is part of GNU Emacs.
|
||||
CC
|
||||
CC GNU Emacs is free software: you can redistribute it and/or modify
|
||||
CC it under the terms of the GNU General Public License as published
|
||||
CC by the Free Software Foundation, either version 3 of the License,
|
||||
CC or (at your option) any later version.
|
||||
CC
|
||||
CC GNU Emacs is distributed in the hope that it will be useful, but
|
||||
CC WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
CC MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
CC General Public License for more details.
|
||||
CC
|
||||
CC You should have received a copy of the GNU General Public License
|
||||
CC along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
.section .text
|
||||
.global _start
|
||||
_start:
|
||||
dnl movl $162, %eax CC SYS_nanosleep
|
||||
dnl leal timespec, %ebx
|
||||
dnl xorl %ecx, %ecx
|
||||
dnl int $0x80
|
||||
leal 8(%esp), %ebp CC ebp = start of load area
|
||||
subl $8, %esp CC (%esp) = primary fd, 4(%esp) = secondary fd
|
||||
movl $-1, 4(%esp)
|
||||
.next_action:
|
||||
movl (%ebp), %edx CC edx = action number
|
||||
andl $-17, %edx
|
||||
cmpl $0, %edx CC open file?
|
||||
je .open_file
|
||||
cmpl $3, %edx CC jump?
|
||||
je .rest_of_exec
|
||||
cmpl $4, %edx CC anonymous mmap?
|
||||
je .do_mmap_anon
|
||||
.do_mmap:
|
||||
subl $24, %esp
|
||||
movl $90, %eax CC SYS_old_mmap
|
||||
movl %esp, %ebx
|
||||
movl 4(%ebp), %ecx CC address
|
||||
movl %ecx, (%esp)
|
||||
movl 16(%ebp), %ecx CC length
|
||||
movl %ecx, 4(%esp)
|
||||
movl 12(%ebp), %ecx CC protection
|
||||
movl %ecx, 8(%esp)
|
||||
movl 20(%ebp), %ecx CC flags
|
||||
movl %ecx, 12(%esp)
|
||||
testl $16, (%ebp) CC primary?
|
||||
movl 28(%esp), %ecx
|
||||
cmovzl 24(%esp), %ecx
|
||||
movl %ecx, 16(%esp) CC fd
|
||||
movl 8(%ebp), %ecx CC offset
|
||||
movl %ecx, 20(%esp)
|
||||
.do_mmap_1:
|
||||
int $0x80
|
||||
addl $24, %esp CC restore esp
|
||||
cmpl $-1, %eax CC mmap failed?
|
||||
je .perror
|
||||
movl 24(%ebp), %ecx CC clear
|
||||
testl %ecx, %ecx
|
||||
jz .continue
|
||||
movl 4(%ebp), %esi CC start of mapping
|
||||
addl 16(%ebp), %esi CC end of mapping
|
||||
subl %ecx, %esi CC start of clear area
|
||||
.again:
|
||||
testl %ecx, %ecx
|
||||
jz .continue
|
||||
subl $1, %ecx
|
||||
movb $0, (%esi, %ecx, 1)
|
||||
jmp .again
|
||||
.continue:
|
||||
leal 28(%ebp), %ebp
|
||||
jmp .next_action
|
||||
.do_mmap_anon:
|
||||
subl $24, %esp
|
||||
movl $90, %eax CC SYS_old_mmap
|
||||
movl %esp, %ebx
|
||||
movl 4(%ebp), %ecx CC address
|
||||
movl %ecx, (%esp)
|
||||
movl 16(%ebp), %ecx CC length
|
||||
movl %ecx, 4(%esp)
|
||||
movl 12(%ebp), %ecx CC protection
|
||||
movl %ecx, 8(%esp)
|
||||
movl 20(%ebp), %ecx CC flags
|
||||
movl %ecx, 12(%esp)
|
||||
movl $-1, 16(%esp) CC fd
|
||||
movl 8(%ebp), %ecx CC offset
|
||||
movl %ecx, 20(%esp)
|
||||
jmp .do_mmap_1
|
||||
.open_file:
|
||||
movl $5, %eax CC SYS_open
|
||||
leal 4(%ebp), %ebx CC ebx = %esp + 8
|
||||
pushl %ebx
|
||||
xorl %ecx, %ecx CC flags = O_RDONLY
|
||||
xorl %edx, %edx CC mode = 0
|
||||
int $0x80
|
||||
cmpl $-1, %eax CC open failed?
|
||||
jle .perror
|
||||
movl %ebp, %esi CC (esi) = original action number
|
||||
popl %ebp CC ebp = start of string
|
||||
movl %ebp, %ecx CC char past separator
|
||||
decl %ebp
|
||||
.nextc:
|
||||
incl %ebp
|
||||
movb (%ebp), %dl CC dl = *ebp
|
||||
cmpb $47, %dl CC dl == '\?'?
|
||||
jne .nextc1
|
||||
leal 1(%ebp), %ecx CC ecx = char past separator
|
||||
.nextc1:
|
||||
cmpb $0, %dl CC dl == 0?
|
||||
jne .nextc
|
||||
addl $4, %ebp CC adjust past ebp prior to rounding
|
||||
andl $-4, %ebp CC round ebp up to the next long
|
||||
testl $16, (%esi) CC original action number & 16?
|
||||
jz .primary
|
||||
movl %eax, 4(%esp) CC secondary fd = eax
|
||||
jmp .next_action
|
||||
.primary:
|
||||
pushl %ebp
|
||||
xorl %esi, %esi CC arg3
|
||||
movl %eax, 4(%esp) CC primary fd = eax
|
||||
xorl %edx, %edx CC arg2
|
||||
movl $15, %ebx CC PR_SET_NAME, arg1 = ecx
|
||||
xorl %edi, %edi CC arg4
|
||||
movl $172, %eax CC SYS_prctl
|
||||
xorl %ebp, %ebp CC arg5
|
||||
int $0x80 CC syscall
|
||||
popl %ebp
|
||||
jmp .next_action
|
||||
.perror:
|
||||
movl %eax, %ebx
|
||||
negl %ebx
|
||||
movl $1, %eax
|
||||
int $0x80
|
||||
.rest_of_exec:
|
||||
movl 8(%esp), %ecx CC ecx = original stack pointer
|
||||
movl (%ecx), %esi CC esi = argc
|
||||
leal 8(%ecx, %esi, 4), %ecx CC ecx = start of environ
|
||||
.skip_environ:
|
||||
movl (%ecx), %esi CC envp[N]
|
||||
addl $4, %ecx
|
||||
testl %esi, %esi CC envp[n] ?
|
||||
jnz .skip_environ CC otherwise, esi is now at the start of auxv
|
||||
.one_auxv:
|
||||
movl (%ecx), %esi CC auxv type
|
||||
leal 8(%ecx), %ecx CC skip to next auxv
|
||||
testl %esi, %esi CC is 0?
|
||||
jz .cleanup
|
||||
cmpl $3, %esi CC is AT_PHDR
|
||||
je .replace_phdr
|
||||
cmpl $4, %esi CC is AT_PHENT?
|
||||
je .replace_phent
|
||||
cmpl $5, %esi CC is AT_PHNUM?
|
||||
je .replace_phnum
|
||||
cmpl $9, %esi CC is AT_ENTRY?
|
||||
je .replace_entry
|
||||
cmpl $7, %esi CC is AT_BASE
|
||||
je .replace_base
|
||||
jmp .one_auxv
|
||||
.replace_phdr:
|
||||
movl 20(%ebp), %esi
|
||||
movl %esi, -4(%ecx)
|
||||
jmp .one_auxv
|
||||
.replace_phent:
|
||||
movl 12(%ebp), %esi
|
||||
movl %esi, -4(%ecx)
|
||||
jmp .one_auxv
|
||||
.replace_phnum:
|
||||
movl 16(%ebp), %esi
|
||||
movl %esi, -4(%ecx)
|
||||
jmp .one_auxv
|
||||
.replace_entry:
|
||||
movl 8(%ebp), %esi
|
||||
movl %esi, -4(%ecx)
|
||||
jmp .one_auxv
|
||||
.replace_base:
|
||||
movl 24(%ebp), %esi
|
||||
movl %esi, -4(%ecx)
|
||||
jmp .one_auxv
|
||||
.cleanup:
|
||||
movl $6, %eax CC SYS_close
|
||||
cmpl $-1, 4(%esp) CC see if interpreter fd is set
|
||||
je .cleanup_1
|
||||
movl 4(%esp), %ebx
|
||||
int $0x80
|
||||
movl $6, %eax CC SYS_close
|
||||
.cleanup_1:
|
||||
movl (%esp), %ebx
|
||||
int $0x80
|
||||
.enter:
|
||||
pushl $0
|
||||
popfl CC restore floating point state
|
||||
movl 8(%esp), %esp CC restore initial stack pointer
|
||||
xorl %edx, %edx CC clear rtld_fini
|
||||
jmpl *4(%ebp) CC entry
|
||||
|
||||
timespec:
|
||||
.long 10
|
||||
.long 10
|
195
exec/loader-x86_64.s
Normal file
195
exec/loader-x86_64.s
Normal file
|
@ -0,0 +1,195 @@
|
|||
define(`CC', `
|
||||
dnl')
|
||||
|
||||
CC Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
CC
|
||||
CC This file is part of GNU Emacs.
|
||||
CC
|
||||
CC GNU Emacs is free software: you can redistribute it and/or modify
|
||||
CC it under the terms of the GNU General Public License as published
|
||||
CC by the Free Software Foundation, either version 3 of the License,
|
||||
CC or (at your option) any later version.
|
||||
CC
|
||||
CC GNU Emacs is distributed in the hope that it will be useful, but
|
||||
CC WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
CC MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
CC General Public License for more details.
|
||||
CC
|
||||
CC You should have received a copy of the GNU General Public License
|
||||
CC along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
.section .text
|
||||
.global _start
|
||||
_start:
|
||||
dnl movq $35, %rax CC SYS_nanosleep
|
||||
dnl leaq timespec(%rip), %rdi
|
||||
dnl xorq %rsi, %rsi
|
||||
dnl syscall
|
||||
popq %r13 CC original SP
|
||||
popq %r15 CC size of load area.
|
||||
movq $-1, %r12 CC r12 is the interpreter fd
|
||||
.next_action:
|
||||
movq (%rsp), %r14 CC action number
|
||||
movq %r14, %r15 CC original action number
|
||||
andq $-17, %r14
|
||||
cmpq $0, %r14 CC open file?
|
||||
je .open_file
|
||||
cmpq $3, %r14 CC jump?
|
||||
je .rest_of_exec
|
||||
cmpq $4, %r14 CC anonymous mmap?
|
||||
je .do_mmap_anon
|
||||
.do_mmap:
|
||||
movq $9, %rax CC SYS_mmap
|
||||
movq 8(%rsp), %rdi CC address
|
||||
movq 16(%rsp), %r9 CC offset
|
||||
movq 24(%rsp), %rdx CC protection
|
||||
movq 32(%rsp), %rsi CC length
|
||||
movq 40(%rsp), %r10 CC flags
|
||||
CC set r8 to the primary fd unless r15 & 16
|
||||
testq $16, %r15
|
||||
movq %r12, %r8
|
||||
cmovzq %rbx, %r8
|
||||
.do_mmap_1:
|
||||
syscall
|
||||
cmpq $-1, %rax CC mmap failed
|
||||
je .perror
|
||||
movq 48(%rsp), %r9 CC clear
|
||||
testq %r9, %r9
|
||||
jz .continue
|
||||
movq 8(%rsp), %r10 CC start of mapping
|
||||
addq 32(%rsp), %r10 CC end of mapping
|
||||
subq %r9, %r10 CC start of clear area
|
||||
.again:
|
||||
testq %r9, %r9
|
||||
jz .continue
|
||||
subq $1, %r9
|
||||
movb $0, (%r10, %r9, 1)
|
||||
jmp .again
|
||||
.continue:
|
||||
leaq 56(%rsp), %rsp
|
||||
jmp .next_action
|
||||
.do_mmap_anon:
|
||||
movq $9, %rax CC SYS_mmap
|
||||
movq 8(%rsp), %rdi CC address
|
||||
movq 16(%rsp), %r9 CC offset
|
||||
movq 24(%rsp), %rdx CC protection
|
||||
movq 32(%rsp), %rsi CC length
|
||||
movq 40(%rsp), %r10 CC flags
|
||||
movq $-1, %r8 CC -1
|
||||
jmp .do_mmap_1
|
||||
.open_file:
|
||||
movq $2, %rax CC SYS_open
|
||||
leaq 8(%rsp), %rdi CC rdi = %rsp + 8
|
||||
xorq %rsi, %rsi CC flags = O_RDONLY
|
||||
xorq %rdx, %rdx CC mode = 0
|
||||
syscall
|
||||
cmpq $-1, %rax CC open failed
|
||||
jle .perror
|
||||
movq %rdi, %rsp CC rsp = start of string
|
||||
subq $1, %rsp
|
||||
movq %rsp, %r14 CC r14 = start of string
|
||||
.nextc:
|
||||
addq $1, %rsp
|
||||
movb (%rsp), %dil CC rdi = *rsp
|
||||
cmpb $47, %dil CC *rsp == '/'?
|
||||
jne .nextc1
|
||||
movq %rsp, %r14 CC r14 = rsp
|
||||
addq $1, %r14 CC r14 = char past separator
|
||||
.nextc1:
|
||||
cmpb $0, %dil CC *rsp == 0?
|
||||
jne .nextc
|
||||
addq $8, %rsp CC adjust past rsp prior to rounding
|
||||
andq $-8, %rsp CC round rsp up to the next quad
|
||||
testq $16, %r15 CC r15 & 16?
|
||||
jz .primary
|
||||
movq %rax, %r12 CC otherwise, move fd to r12
|
||||
jmp .next_action
|
||||
.primary:
|
||||
movq %rax, %rbx CC if not, move fd to rbx
|
||||
movq $157, %rax CC SYS_prctl
|
||||
movq $15, %rdi CC PR_SET_NAME
|
||||
movq %r14, %rsi CC arg1
|
||||
xorq %rdx, %rdx CC arg2
|
||||
xorq %r10, %r10 CC arg3
|
||||
xorq %r8, %r8 CC arg4
|
||||
xorq %r9, %r9 CC arg5
|
||||
syscall
|
||||
jmp .next_action
|
||||
.perror:
|
||||
movq %rax, %r12 CC error code
|
||||
negq %r12
|
||||
movq $1, %rax CC SYS_write
|
||||
movq $1, %rdi CC stdout
|
||||
leaq error(%rip), %rsi CC buffer
|
||||
movq $23, %rdx CC count
|
||||
syscall
|
||||
movq $60, %rax CC SYS_exit
|
||||
movq %r12, %rdi CC code
|
||||
syscall
|
||||
.rest_of_exec: CC rsp now points to six quads:
|
||||
movq %rsp, %r8 CC now, they are r8
|
||||
movq %r13, %rsp CC restore SP
|
||||
popq %r10 CC argc
|
||||
leaq 8(%rsp,%r10,8), %rsp CC now at start of environ
|
||||
.skip_environ:
|
||||
popq %r10 CC envp[N]
|
||||
testq %r10, %r10 CC envp[n]?
|
||||
jnz .skip_environ CC otherwise, rsp is now at the start of auxv
|
||||
.one_auxv:
|
||||
popq %rcx CC auxv type
|
||||
addq $8, %rsp CC skip value
|
||||
testq %rcx, %rcx CC is 0?
|
||||
jz .cleanup
|
||||
cmpq $3, %rcx CC is AT_PHDR?
|
||||
je .replace_phdr
|
||||
cmpq $4, %rcx CC is AT_PHENT?
|
||||
je .replace_phent
|
||||
cmpq $5, %rcx CC is AT_PHNUM?
|
||||
je .replace_phnum
|
||||
cmpq $9, %rcx CC is AT_ENTRY?
|
||||
je .replace_entry
|
||||
cmpq $7, %rcx CC is AT_BASE?
|
||||
je .replace_base
|
||||
jmp .one_auxv
|
||||
.replace_phdr:
|
||||
movq 40(%r8), %r9
|
||||
movq %r9, -8(%rsp) CC set at_phdr
|
||||
jmp .one_auxv
|
||||
.replace_phent:
|
||||
movq 24(%r8), %r9
|
||||
movq %r9, -8(%rsp) CC set at_phent
|
||||
jmp .one_auxv
|
||||
.replace_phnum:
|
||||
movq 32(%r8), %r9
|
||||
movq %r9, -8(%rsp) CC set at_phnum
|
||||
jmp .one_auxv
|
||||
.replace_entry:
|
||||
movq 16(%r8), %r9
|
||||
movq %r9, -8(%rsp) CC set at_entry
|
||||
jmp .one_auxv
|
||||
.replace_base:
|
||||
movq 48(%r8), %r9
|
||||
movq %r9, -8(%rsp) CC set at_base
|
||||
jmp .one_auxv
|
||||
.cleanup:
|
||||
movq $3, %rax CC SYS_close
|
||||
cmpq $-1, %r12 CC see if interpreter fd is set
|
||||
je .cleanup_1
|
||||
movq %r12, %rdi
|
||||
syscall
|
||||
movq $3, %rax CC SYS_close
|
||||
.cleanup_1:
|
||||
movq %rbx, %rdi
|
||||
syscall
|
||||
.enter:
|
||||
pushq $0
|
||||
popfq CC clear FP state
|
||||
movq %r13, %rsp CC restore SP
|
||||
xorq %rdx, %rdx CC clear rtld_fini
|
||||
jmpq *8(%r8) CC entry
|
||||
|
||||
error:
|
||||
.ascii "_start: internal error."
|
||||
timespec:
|
||||
.quad 10
|
||||
.quad 10
|
43
exec/mipsel-user.h
Normal file
43
exec/mipsel-user.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
/* Program execution for Emacs.
|
||||
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
|
||||
|
||||
#ifndef _MIPSEL_USER_H_
|
||||
#define _MIPSEL_USER_H_
|
||||
|
||||
#include <sys/user.h>
|
||||
|
||||
#ifndef ELF_NGREG
|
||||
#define ELF_NGREG 45
|
||||
#endif /* ELF_NGREG */
|
||||
|
||||
|
||||
|
||||
/* This file defines a structure containing user mode general purpose
|
||||
registers on 32-bit mipsel systems. */
|
||||
|
||||
struct mipsel_regs
|
||||
{
|
||||
/* General purpose registers. */
|
||||
uint64_t gregs[ELF_NGREG];
|
||||
};
|
||||
|
||||
#endif /* _MIPSEL_USER_H_ */
|
||||
|
289
exec/mipsfpu.c
Normal file
289
exec/mipsfpu.c
Normal file
|
@ -0,0 +1,289 @@
|
|||
/* Program execution for Emacs.
|
||||
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <config.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "mipsfpu.h"
|
||||
|
||||
|
||||
|
||||
/* OABI MIPS systems support several different modes of execution.
|
||||
Each mode differs in the size and utilization of the hardware
|
||||
floating-point registers.
|
||||
|
||||
Linux normally sets the floating point mode to one appropriate for
|
||||
execution, taking into account the floating point modes of the
|
||||
interpreter and executable binaries. However, this logic is
|
||||
forsaken when the `execve' system call is overwritten.
|
||||
|
||||
Thus, the correct floating point mode must be determined and set
|
||||
within the loader binary. */
|
||||
|
||||
|
||||
|
||||
/* Various constants used throughout this code. */
|
||||
|
||||
#define MIPS_ABI_FP_ANY 0 /* FP ABI doesn't matter */
|
||||
#define MIPS_ABI_FP_DOUBLE 1 /* -mdouble-float */
|
||||
#define MIPS_ABI_FP_SINGLE 2 /* -msingle-float */
|
||||
#define MIPS_ABI_FP_SOFT 3 /* -msoft-float */
|
||||
#define MIPS_ABI_FP_OLD_64 4 /* -mips32r2 -mfp64 */
|
||||
#define MIPS_ABI_FP_XX 5 /* -mfpxx */
|
||||
#define MIPS_ABI_FP_64 6 /* -mips32r2 -mfp64 */
|
||||
#define MIPS_ABI_FP_64A 7 /* -mips32r2 -mfp64 -mno-odd-spreg */
|
||||
|
||||
#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used. */
|
||||
#define EF_MIPS_PIC 2 /* Contains PIC code. */
|
||||
#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence. */
|
||||
#define EF_MIPS_XGOT 8
|
||||
#define EF_MIPS_64BIT_WHIRL 16
|
||||
#define EF_MIPS_ABI2 32
|
||||
#define EF_MIPS_ABI_ON32 64
|
||||
#define EF_MIPS_FP64 512 /* Uses FP64 (12 callee-saved). */
|
||||
#define EF_MIPS_NAN2008 1024 /* Uses IEEE 754-2008 NaN encoding. */
|
||||
#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level. */
|
||||
|
||||
|
||||
|
||||
/* Structure describing the requirements of a single floating-point
|
||||
ABI. */
|
||||
|
||||
struct mode_description
|
||||
{
|
||||
/* Whether or not the ABI only executes single precision
|
||||
instructions, and can operate in both 32-bit or 64-bit floating
|
||||
point mode. */
|
||||
bool single;
|
||||
|
||||
/* Whether or not the ABI performs floating point operations in
|
||||
software, using integer registers. */
|
||||
bool soft;
|
||||
|
||||
/* Whether or not the ABI requires the use of 64-bit floating point
|
||||
registers. */
|
||||
bool fr1;
|
||||
|
||||
/* Whether or not the ABI requires the use of 64-bit floating point
|
||||
registers on NABI systems, and 32-bit ones on OABI systems. */
|
||||
bool frdefault;
|
||||
|
||||
/* Whether or not this ABI requires single precision floating point
|
||||
emulation. */
|
||||
bool fre;
|
||||
};
|
||||
|
||||
static struct mode_description fpu_reqs[] =
|
||||
{
|
||||
[MIPS_ABI_FP_ANY] = { true, true, true, true, true, },
|
||||
[MIPS_ABI_FP_DOUBLE] = { false, false, false, true, true, },
|
||||
[MIPS_ABI_FP_SINGLE] = { true, false, false, false, false, },
|
||||
[MIPS_ABI_FP_SOFT] = { false, true, false, false, false, },
|
||||
[MIPS_ABI_FP_OLD_64] = { false, false, false, false, false, },
|
||||
[MIPS_ABI_FP_XX] = { false, false, true, true, true, },
|
||||
[MIPS_ABI_FP_64] = { false, false, true, false, false, },
|
||||
[MIPS_ABI_FP_64A] = { false, false, true, false, true, },
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Return whether or not the given floating-point ABI is valid. */
|
||||
|
||||
static bool
|
||||
valid_abi_p (int abi)
|
||||
{
|
||||
switch (abi)
|
||||
{
|
||||
case MIPS_ABI_FP_ANY:
|
||||
case MIPS_ABI_FP_DOUBLE:
|
||||
case MIPS_ABI_FP_SINGLE:
|
||||
case MIPS_ABI_FP_SOFT:
|
||||
case MIPS_ABI_FP_OLD_64:
|
||||
case MIPS_ABI_FP_XX:
|
||||
case MIPS_ABI_FP_64:
|
||||
case MIPS_ABI_FP_64A:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the floating point mode appropriate for the specified
|
||||
floating point ABI. */
|
||||
|
||||
static int
|
||||
fp_mode_for_abi (int abi)
|
||||
{
|
||||
struct mode_description *desc;
|
||||
|
||||
desc = &fpu_reqs[abi];
|
||||
|
||||
if (desc->fre)
|
||||
return FP_FRE;
|
||||
else if (desc->fr1)
|
||||
return FP_FR1;
|
||||
|
||||
return FP_FR0;
|
||||
}
|
||||
|
||||
/* Determine whether or not the CPU is capable of operating in FR0
|
||||
floating point mode. */
|
||||
|
||||
bool
|
||||
cpu_supports_fr0_p (void)
|
||||
{
|
||||
#if defined __mips_isa_rev && __mips_isa_rev >= 6
|
||||
return true;
|
||||
#else /* !defined __mips_isa_rev | mips_isa_rev < 6 */
|
||||
return false;
|
||||
#endif /* defined __mips_isa_rev && mips_isa_rev >= 6 */
|
||||
}
|
||||
|
||||
/* Determine the FPU mode for the executable whose ELF header is
|
||||
HEADER. If INTERPRETER is non-NULL, also take an interpreter whose
|
||||
header is INTERPRETER into account.
|
||||
|
||||
ABIFLAGS should be HEADER's corresponding PT_MIPS_ABIFLAGS program
|
||||
header, and ABIFLAGS1 should be that of INTERPRETER, if set. Both
|
||||
fields may be NULL if no PT_MIPS_ABIFLAGS header is present; in
|
||||
that case, use HEADER->e_flags to determine the ABI instead.
|
||||
|
||||
Return the FPU mode in *MODE. Value is 0 upon success, 1
|
||||
otherwise, with errno set. */
|
||||
|
||||
int
|
||||
determine_fpu_mode (elf_header *header, elf_header *interpreter,
|
||||
int *mode, struct mips_elf_abi_flags *abiflags,
|
||||
struct mips_elf_abi_flags *abiflags1)
|
||||
{
|
||||
int exec_abi, interpreter_abi;
|
||||
struct mode_description *exec_desc, *interpreter_desc, common;
|
||||
|
||||
/* Figure out the executable's floating point ABI. First, consult
|
||||
header->e_flags, and use the old 64-bit floating point ABI if it
|
||||
is specified. */
|
||||
|
||||
exec_abi = MIPS_ABI_FP_ANY;
|
||||
|
||||
/* First, check HEADER->e_flags. */
|
||||
|
||||
if (header->e_flags & EF_MIPS_FP64)
|
||||
exec_abi = MIPS_ABI_FP_OLD_64;
|
||||
|
||||
/* Next, use ABIFLAGS if it exists. */
|
||||
|
||||
if (abiflags && valid_abi_p (abiflags->fp_abi))
|
||||
exec_abi = abiflags->fp_abi;
|
||||
else if (abiflags)
|
||||
{
|
||||
errno = ENOEXEC;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Now determine that of the interpreter. */
|
||||
|
||||
interpreter_abi = MIPS_ABI_FP_ANY;
|
||||
|
||||
if (interpreter)
|
||||
{
|
||||
if (interpreter->e_flags & EF_MIPS_FP64)
|
||||
interpreter_abi = MIPS_ABI_FP_OLD_64;
|
||||
|
||||
if (abiflags1 && valid_abi_p (abiflags->fp_abi))
|
||||
interpreter_abi = abiflags->fp_abi;
|
||||
else if (abiflags1)
|
||||
{
|
||||
errno = ELIBBAD;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* If no interpreter flag is set, just return that of the
|
||||
executable. */
|
||||
|
||||
if (!interpreter)
|
||||
{
|
||||
*mode = fp_mode_for_abi (exec_abi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Otherwise, compare both ABIs and try to find one which will run
|
||||
both kinds of code.
|
||||
|
||||
First, see if there's an easy way out: both ABIs are identical,
|
||||
or one ABI is MIPS_ABI_FP_ANY. */
|
||||
|
||||
if (exec_abi == interpreter_abi)
|
||||
{
|
||||
*mode = fp_mode_for_abi (exec_abi);
|
||||
return 0;
|
||||
}
|
||||
else if (exec_abi == MIPS_ABI_FP_ANY)
|
||||
{
|
||||
*mode = fp_mode_for_abi (interpreter_abi);
|
||||
return 0;
|
||||
}
|
||||
else if (interpreter_abi == MIPS_ABI_FP_ANY)
|
||||
{
|
||||
*mode = fp_mode_for_abi (exec_abi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If that doesn't work, compare various characteristics of both
|
||||
ABIs and select an appropriate floating point mode. */
|
||||
|
||||
exec_desc = &fpu_reqs[exec_abi];
|
||||
interpreter_desc = &fpu_reqs[interpreter_abi];
|
||||
|
||||
/* Merge both sets of requirements. */
|
||||
common.single = exec_desc->single && interpreter_desc->single;
|
||||
common.soft = exec_desc->soft && interpreter_desc->soft;
|
||||
common.fr1 = exec_desc->fr1 && interpreter_desc->fr1;
|
||||
common.frdefault = exec_desc->frdefault && interpreter_desc->frdefault;
|
||||
common.fre = exec_desc->fre && interpreter_desc->fre;
|
||||
|
||||
/* Default to a mode capable of running code expecting 32-bit
|
||||
registers. */
|
||||
|
||||
if (!(header->e_flags & EF_MIPS_ABI2))
|
||||
*mode = FP_FR0;
|
||||
else
|
||||
/* But in this case, use FR1. */
|
||||
*mode = FP_FR1;
|
||||
|
||||
if (common.fre && !common.frdefault && !common.fr1)
|
||||
/* Floating point emulation mode is required. */
|
||||
*mode = FP_FRE;
|
||||
else if ((common.fr1 && common.frdefault)
|
||||
|| (common.single && !common.frdefault)
|
||||
|| common.fr1)
|
||||
/* 64-bit mode is required. */
|
||||
*mode = FP_FR1;
|
||||
else if (!common.fre && !common.frdefault
|
||||
&& !common.fr1 && !common.single
|
||||
&& !common.soft)
|
||||
{
|
||||
/* The floating point modes specified are incompatible. */
|
||||
errno = ELIBBAD;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
82
exec/mipsfpu.h
Normal file
82
exec/mipsfpu.h
Normal file
|
@ -0,0 +1,82 @@
|
|||
/* Program execution for Emacs.
|
||||
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
|
||||
|
||||
#ifndef _MIPSFPU_H_
|
||||
#define _MIPSFPU_H_
|
||||
|
||||
#include "exec.h"
|
||||
|
||||
struct mips_elf_abi_flags
|
||||
{
|
||||
/* Version of flags structure. */
|
||||
uint16_t version;
|
||||
|
||||
/* The level of the ISA: 1-5, 32, 64. */
|
||||
uint8_t isa_level;
|
||||
|
||||
/* The revision of ISA: 0 for MIPS V and below, 1-n otherwise. */
|
||||
uint8_t isa_rev;
|
||||
|
||||
/* The size of general purpose registers. */
|
||||
uint8_t gpr_size;
|
||||
|
||||
/* The size of co-processor 1 registers. */
|
||||
uint8_t cpr1_size;
|
||||
|
||||
/* The size of co-processor 2 registers. */
|
||||
uint8_t cpr2_size;
|
||||
|
||||
/* The floating-point ABI. */
|
||||
uint8_t fp_abi;
|
||||
|
||||
/* Mask of processor-specific extensions. */
|
||||
uint32_t isa_ext;
|
||||
|
||||
/* Mask of ASEs used. */
|
||||
uint32_t ases;
|
||||
|
||||
/* Mask of general flags. */
|
||||
uint32_t flags1;
|
||||
|
||||
/* Mask of general flags. */
|
||||
uint32_t flags2;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Floating point modes. */
|
||||
|
||||
#define FP_FR0 0
|
||||
#define FP_FR1 1
|
||||
#define FP_FRE 3
|
||||
|
||||
|
||||
|
||||
/* Defined in mipsfpu.c. */
|
||||
|
||||
extern bool cpu_supports_fr0_p (void);
|
||||
extern int determine_fpu_mode (elf_header *, elf_header *,
|
||||
int *, struct mips_elf_abi_flags *,
|
||||
struct mips_elf_abi_flags *);
|
||||
|
||||
|
||||
|
||||
#endif /* _MIPSFPU_H_ */
|
105
exec/test.c
Normal file
105
exec/test.c
Normal file
|
@ -0,0 +1,105 @@
|
|||
/* Program execution for Emacs.
|
||||
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "exec.h"
|
||||
|
||||
|
||||
|
||||
static void
|
||||
print_usage (void)
|
||||
{
|
||||
fprintf (stderr, "test loader-name program [args...]\n"
|
||||
"Run the given program using the specified loader.\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
extern char **environ;
|
||||
|
||||
/* This program uses libexec to wrap the execution of a child
|
||||
process. */
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
pid_t pid, child;
|
||||
int sig;
|
||||
sigset_t sigset;
|
||||
|
||||
/* Check that there are a sufficient number of arguments. */
|
||||
|
||||
if (argc < 3)
|
||||
{
|
||||
print_usage ();
|
||||
return 1;
|
||||
}
|
||||
|
||||
exec_init (argv[1]);
|
||||
|
||||
/* Block SIGCHLD to avoid reentrant modification of the child
|
||||
process list. */
|
||||
|
||||
sigemptyset (&sigset);
|
||||
sigaddset (&sigset, SIGCHLD);
|
||||
sigprocmask (SIG_BLOCK, &sigset, NULL);
|
||||
|
||||
if (!(pid = fork ()))
|
||||
{
|
||||
tracing_execve (argv[2], argv + 2, environ);
|
||||
fprintf (stderr, "tracing_execve: %s\n",
|
||||
strerror (errno));
|
||||
exit (1);
|
||||
}
|
||||
else if (after_fork (pid))
|
||||
{
|
||||
fprintf (stderr, "after_fork: %s\n",
|
||||
strerror (errno));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* Now start waiting for child processes to exit. */
|
||||
|
||||
while (true)
|
||||
{
|
||||
child = exec_waitpid (-1, &sig, 0);
|
||||
|
||||
/* If pid is -1, a system call has been handled. */
|
||||
|
||||
if (child == -1)
|
||||
continue;
|
||||
|
||||
/* If the main process exits, then exit as well. */
|
||||
|
||||
if (child == pid && !WIFSTOPPED (sig))
|
||||
return (WIFEXITED (sig)
|
||||
? WEXITSTATUS (sig)
|
||||
: WTERMSIG (sig));
|
||||
}
|
||||
}
|
1432
exec/trace.c
Normal file
1432
exec/trace.c
Normal file
File diff suppressed because it is too large
Load diff
225
java/AndroidManifest.xml.in
Normal file
225
java/AndroidManifest.xml.in
Normal file
|
@ -0,0 +1,225 @@
|
|||
<!-- @configure_input@
|
||||
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. -->
|
||||
|
||||
<!-- targetSandboxVersion must be 1. Otherwise, fascist security
|
||||
restrictions prevent Emacs from making HTTP connections. -->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.gnu.emacs"
|
||||
android:targetSandboxVersion="1"
|
||||
android:installLocation="auto"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
@ANDROID_SHARED_USER_ID@
|
||||
@ANDROID_SHARED_USER_NAME@
|
||||
android:versionCode="@emacs_major_version@"
|
||||
android:versionName="@version@">
|
||||
|
||||
<!-- Paste in every permission in existence so Emacs can do
|
||||
anything. -->
|
||||
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
||||
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.SET_WALLPAPER" />
|
||||
<!-- Despite the claim that WRITE_EXTERNAL_STORAGE also covers
|
||||
reading from external storage, specifying READ_EXTERNAL_STORAGE
|
||||
seems to still be necessary on some versions of Android.
|
||||
(bug#64445) -->
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.SEND_SMS" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_SMS" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_MMS"/>
|
||||
<uses-permission android:name="android.permission.WRITE_SMS"/>
|
||||
<uses-permission android:name="android.permission.READ_SMS"/>
|
||||
<uses-permission android:name="android.permission.NFC" />
|
||||
<uses-permission android:name="android.permission.TRANSMIT_IR" />
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
|
||||
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES"/>
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
|
||||
<!-- This is required on Android 11 or later to access /sdcard. -->
|
||||
|
||||
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
|
||||
|
||||
<uses-sdk android:minSdkVersion="@ANDROID_MIN_SDK@"
|
||||
android:targetSdkVersion="33"/>
|
||||
|
||||
<application android:name="org.gnu.emacs.EmacsApplication"
|
||||
android:label="Emacs"
|
||||
android:icon="@drawable/emacs"
|
||||
android:hardwareAccelerated="true"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/EmacsStyle"
|
||||
android:debuggable="@ANDROID_DEBUGGABLE@"
|
||||
android:allowBackup="true"
|
||||
android:extractNativeLibs="true">
|
||||
|
||||
<activity android:name="org.gnu.emacs.EmacsActivity"
|
||||
android:launchMode="singleInstance"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:exported="true"
|
||||
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name="org.gnu.emacs.EmacsOpenActivity"
|
||||
android:taskAffinity="open.dialog"
|
||||
android:excludeFromRecents="true"
|
||||
android:exported="true">
|
||||
|
||||
<!-- Allow Emacs to open all kinds of files known to Android. -->
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW"/>
|
||||
<action android:name="android.intent.action.EDIT"/>
|
||||
<action android:name="android.intent.action.PICK"/>
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
|
||||
<data android:mimeType="image/aces"/>
|
||||
<data android:mimeType="image/avci"/>
|
||||
<data android:mimeType="image/avcs"/>
|
||||
<data android:mimeType="image/avif"/>
|
||||
<data android:mimeType="image/bmp"/>
|
||||
<data android:mimeType="image/cgm"/>
|
||||
<data android:mimeType="image/dicom-rle"/>
|
||||
<data android:mimeType="image/dpx"/>
|
||||
<data android:mimeType="image/emf"/>
|
||||
<data android:mimeType="image/example"/>
|
||||
<data android:mimeType="image/fits"/>
|
||||
<data android:mimeType="image/g3fax"/>
|
||||
<data android:mimeType="image/heic"/>
|
||||
<data android:mimeType="image/heic-sequence"/>
|
||||
<data android:mimeType="image/heif"/>
|
||||
<data android:mimeType="image/heif-sequence"/>
|
||||
<data android:mimeType="image/hej2k"/>
|
||||
<data android:mimeType="image/hsj2"/>
|
||||
<data android:mimeType="image/jls"/>
|
||||
<data android:mimeType="image/jp2"/>
|
||||
<data android:mimeType="image/jph"/>
|
||||
<data android:mimeType="image/jphc"/>
|
||||
<data android:mimeType="image/jpm"/>
|
||||
<data android:mimeType="image/jpx"/>
|
||||
<data android:mimeType="image/jxr"/>
|
||||
<data android:mimeType="image/jxrA"/>
|
||||
<data android:mimeType="image/jxrS"/>
|
||||
<data android:mimeType="image/jxs"/>
|
||||
<data android:mimeType="image/jxsc"/>
|
||||
<data android:mimeType="image/jxsi"/>
|
||||
<data android:mimeType="image/jxss"/>
|
||||
<data android:mimeType="image/ktx"/>
|
||||
<data android:mimeType="image/ktx2"/>
|
||||
<data android:mimeType="image/naplps"/>
|
||||
<data android:mimeType="image/png"/>
|
||||
<data android:mimeType="image/prs.btif"/>
|
||||
<data android:mimeType="image/prs.pti"/>
|
||||
<data android:mimeType="image/pwg-raster"/>
|
||||
<data android:mimeType="image/svg+xml"/>
|
||||
<data android:mimeType="image/t38"/>
|
||||
<data android:mimeType="image/tiff"/>
|
||||
<data android:mimeType="image/tiff-fx"/>
|
||||
<data android:mimeType="image/xpm"/>
|
||||
<data android:mimeType="text/*"/>
|
||||
<data android:mimeType="application/*xml"/>
|
||||
<data android:mimeType="application/atom+xml"/>
|
||||
<data android:mimeType="application/dxf"/>
|
||||
<data android:mimeType="application/ecmascript"/>
|
||||
<data android:mimeType="application/javascript"/>
|
||||
<data android:mimeType="application/json"/>
|
||||
<data android:mimeType="application/*log*"/>
|
||||
<data android:mimeType="application/octet-stream"/>
|
||||
<data android:mimeType="application/soap+xm"/>
|
||||
<data android:mimeType="application/x-caramel"/>
|
||||
<data android:mimeType="application/x-klaunch"/>
|
||||
<data android:mimeType="application/x-latex"/>
|
||||
<data android:mimeType="application/x-sh"/>
|
||||
<data android:mimeType="application/x-tcl"/>
|
||||
<data android:mimeType="application/x-tex*"/>
|
||||
<data android:mimeType="application/x-troff*"/>
|
||||
<data android:mimeType="application/xhtml+xml"/>
|
||||
<data android:mimeType="application/xml*"/>
|
||||
<data android:mimeType="application/zip"/>
|
||||
<data android:mimeType="application/x-zip-compressed"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name="org.gnu.emacs.EmacsMultitaskActivity"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:exported="true"
|
||||
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"/>
|
||||
|
||||
<activity android:autoRemoveFromRecents="true"
|
||||
android:label="Emacs options"
|
||||
android:exported="true"
|
||||
android:name=".EmacsPreferencesActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.APPLICATION_PREFERENCES" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- Android 6 and earlier don't display ``application
|
||||
preferences'' activities in Settings, so display the
|
||||
preferences activity as a launcher icon instead. -->
|
||||
|
||||
<activity android:autoRemoveFromRecents="true"
|
||||
android:label="Emacs options"
|
||||
android:enabled="@bool/isBeforeNougat"
|
||||
android:exported="@bool/isBeforeNougat"
|
||||
android:icon="@drawable/emacs_wrench"
|
||||
android:name=".EmacsLauncherPreferencesActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<provider android:name="org.gnu.emacs.EmacsDocumentsProvider"
|
||||
android:authorities="org.gnu.emacs"
|
||||
android:exported="true"
|
||||
android:grantUriPermissions="true"
|
||||
android:permission="android.permission.MANAGE_DOCUMENTS"
|
||||
android:enabled="@bool/isAtLeastKitKat">
|
||||
<intent-filter>
|
||||
<action
|
||||
android:name="android.content.action.DOCUMENTS_PROVIDER"/>
|
||||
</intent-filter>
|
||||
</provider>
|
||||
|
||||
<service android:name="org.gnu.emacs.EmacsService"
|
||||
android:directBootAware="false"
|
||||
android:enabled="true"
|
||||
android:exported="false"
|
||||
android:label="GNU Emacs service"/>
|
||||
</application>
|
||||
</manifest>
|
977
java/INSTALL
Normal file
977
java/INSTALL
Normal file
|
@ -0,0 +1,977 @@
|
|||
Installation instructions for Android
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
See the end of the file for license conditions.
|
||||
|
||||
Please read the entirety of this file before attempting to build Emacs
|
||||
as an application package which can run on Android devices.
|
||||
|
||||
When building from the source repository, make sure to read
|
||||
INSTALL.REPO as well.
|
||||
|
||||
|
||||
|
||||
Android is an unusual operating system in that program binaries cannot
|
||||
be produced on computers running Android themselves. Instead, they
|
||||
must be built on some other computer using a set of tools known as the
|
||||
``Android SDK'' (Software Development Kit) and the ``Android NDK''
|
||||
(Native Development Kit.) Appropriate versions of both must be
|
||||
obtained to build GNU Emacs; after being built, the generated binaries
|
||||
will work on almost all Android devices. This document does not
|
||||
elaborate on how both sets of tools can be obtained. However, for
|
||||
your freedom's sake, you should use the Android SDK provided by the
|
||||
Debian project.
|
||||
|
||||
In addition to the Android SDK and Android NDK, Emacs also requires
|
||||
the Java compiler from OpenJDK 1.7.0 to be installed on your system,
|
||||
along with a working `m4' macro processor. Building on GNU systems is
|
||||
all that is officially supported. We are told that Mac OS works too,
|
||||
and other Unix systems will likely work as well, but MS Windows and
|
||||
Cygwin will not.
|
||||
|
||||
Once all of those tools are obtained, you may invoke the `configure'
|
||||
script like so:
|
||||
|
||||
./configure --with-android=/path/to/android.jar \
|
||||
ANDROID_CC=/path/to/android/ndk/cc \
|
||||
SDK_BUILD_TOOLS=/path/to/sdk/build/tools
|
||||
|
||||
Replacing the paths in the command line above with:
|
||||
|
||||
- the path to the `android.jar' headers which come with the Android
|
||||
SDK. They must correspond to Android version 13 (API level 33) or
|
||||
later.
|
||||
|
||||
- the path to the C compiler in the Android NDK, for the kind of CPU
|
||||
you are building Emacs to run on.
|
||||
|
||||
- the path to the directory in the Android SDK containing binaries
|
||||
such as `aapt', `apksigner', and `d8'. These are used to build
|
||||
the application package.
|
||||
|
||||
Where the type of CPU can either be `armeabi', `armv7*', `i686',
|
||||
`x86_64', `mips', or `mips64'.
|
||||
|
||||
After the configuration process completes, you may run:
|
||||
|
||||
make all
|
||||
|
||||
Once `make' finishes, there should be a file in the `java' directory
|
||||
named along the lines of:
|
||||
|
||||
emacs-<version>-<api-version>-<abi>.apk
|
||||
|
||||
where <api-version> is the oldest version of Android that the package
|
||||
will run on, and <abi> is the type of Android machine the package was
|
||||
built for.
|
||||
|
||||
The generated package can be uploaded onto an SD card (or similar
|
||||
medium) and installed on-device.
|
||||
|
||||
|
||||
BUILDING WITH OLD NDK VERSIONS
|
||||
|
||||
Building Emacs with an old version of the Android NDK requires special
|
||||
setup. This is because there is no separate C compiler binary for
|
||||
each version of Android in those versions of the NDK.
|
||||
|
||||
Before running `configure', you must identify three variables:
|
||||
|
||||
- What kind of Android system you are building Emacs for.
|
||||
|
||||
- The minimum API version of Android you want to build Emacs for.
|
||||
|
||||
- The locations of the system root and include files for that
|
||||
version of Android in the NDK.
|
||||
|
||||
That information must then be specified as arguments to the NDK C
|
||||
compiler. For example:
|
||||
|
||||
./configure [...] \
|
||||
ANDROID_CC="i686-linux-android-gcc \
|
||||
--sysroot=/path/to/ndk/platforms/android-14/arch-x86/"
|
||||
ANDROID_CFLAGS="-isystem /path/to/ndk/sysroot/usr/include \
|
||||
-isystem /path/to/ndk/sysroot/usr/include/i686-linux-android \
|
||||
-D__ANDROID_API__=14"
|
||||
|
||||
Where __ANDROID_API__ and the version identifier in
|
||||
"platforms/android-14" defines the version of Android you are building
|
||||
for, and the include directories specify the paths to the relevant
|
||||
Android headers. In addition, it may be necessary to specify
|
||||
"-gdwarf-2", due to a bug in the Android NDK.
|
||||
|
||||
Even older versions of the Android SDK do not require the extra
|
||||
`-isystem' directives.
|
||||
|
||||
Emacs is known to run on Android 2.2 (API version 8) or later, with
|
||||
the NDK r10b or later. We wanted to make Emacs work on even older
|
||||
versions of Android, but they are missing the required JNI graphics
|
||||
library that allows Emacs to display text from C code.
|
||||
|
||||
Due to an extremely nasty bug in the Android 2.2 system, the generated
|
||||
Emacs package cannot be compressed in builds for Android 2.2. As a
|
||||
result, the Emacs package will be approximately 100 megabytes larger
|
||||
than a compressed package for a newer version of Android.
|
||||
|
||||
|
||||
BUILDING C++ DEPENDENCIES
|
||||
|
||||
With a new version of the NDK, dependencies containing C++ code should
|
||||
build without any futher configuration. However, older versions
|
||||
require that you use the ``make_standalone_toolchain.py'' script in
|
||||
the NDK distribution to create a ``standalone toolchain'', and use
|
||||
that instead, in order for C++ headers to be found.
|
||||
|
||||
See https://developer.android.com/ndk/guides/standalone_toolchain for
|
||||
more details; when a ``standalone toolchain'' is specified, the
|
||||
configure script will try to determine the location of the C++
|
||||
compiler based on the C compiler specified. If that automatic
|
||||
detection does not work, you can specify a C++ compiler yourself, like
|
||||
so:
|
||||
|
||||
./configure --with-ndk-cxx=/path/to/toolchain/bin/i686-linux-android-g++
|
||||
|
||||
Some versions of the NDK have a bug, where GCC fails to locate
|
||||
``stddef.h'' after being copied to a standalone toolchain. To work
|
||||
around this problem (which normally exhibits itself when building C++
|
||||
code), add:
|
||||
|
||||
-isystem /path/to/toolchain/include/c++/4.9.x
|
||||
|
||||
to ANDROID_CFLAGS.
|
||||
|
||||
|
||||
DEBUG AND RELEASE BUILDS
|
||||
|
||||
Android makes a distinction between ``debug'' and ``release'' builds
|
||||
of applications. With ``release'' builds, the system will apply
|
||||
stronger optimizations to the application at the cost of being unable
|
||||
to debug them with the steps in etc/DEBUG.
|
||||
|
||||
Emacs is built as a debuggable package by default, but:
|
||||
|
||||
./configure --without-android-debug
|
||||
|
||||
will create a release build of Emacs instead. This may be useful when
|
||||
running Emacs on resource constrained machines.
|
||||
|
||||
If you are building an Emacs package for redistribution, we urge you
|
||||
to provide both debug and release versions.
|
||||
|
||||
|
||||
BUILDING WITH A SHARED USER ID
|
||||
|
||||
Sometimes it may be desirable to build Emacs so that it is able to
|
||||
access executables and application data from another program. To
|
||||
achieve this, that other program must have a ``shared user ID'', and
|
||||
be signed with the same signing key used to sign Emacs (normally
|
||||
`emacs.keystore'.)
|
||||
|
||||
Once you have both that signing key and its ``shared user ID'', you
|
||||
can give it to configure:
|
||||
|
||||
./configure --with-shared-user-id=MY.SHARED.USER.ID
|
||||
|
||||
For instance,
|
||||
|
||||
./configure --with-shared-user-id=com.termux
|
||||
|
||||
will result in Termux (https://termux.dev)'s application data being
|
||||
accessible to Emacs, within its own application data directory located
|
||||
at `/data/data/com.termux/files'.
|
||||
|
||||
Don't do this if you already have Emacs installed with a different
|
||||
shared user ID, as the system does not allow programs to change their
|
||||
user IDs after being installed.
|
||||
|
||||
|
||||
BUILDING WITH THIRD PARTY LIBRARIES
|
||||
|
||||
The Android NDK does not support the usual ways of locating third
|
||||
party libraries, especially not via `pkg-config'. Instead, it uses
|
||||
its own system called `ndk-build'. The one exception to this rule is
|
||||
zlib, which is considered a part of the Android OS itself and is
|
||||
available on all devices running Android.
|
||||
|
||||
Android also requires that each application include its own
|
||||
dependencies, as the system makes no guarantee about the existence of
|
||||
any particular library.
|
||||
|
||||
Emacs is not built with the `ndk-build' system. Instead, it is built
|
||||
with Autoconf and Make.
|
||||
|
||||
However, it supports building and including dependencies which use the
|
||||
similarly Make-based `ndk-build' system.
|
||||
|
||||
To use dependencies built through `ndk-build', you must specify a list
|
||||
of directories within which Emacs will search for ``Android.mk''
|
||||
files, like so:
|
||||
|
||||
./configure "--with-ndk-path=directory1 directory2"
|
||||
|
||||
If `configure' complains about not being able to find
|
||||
``libc++_shared.so'', then you must locate that file in your copy of
|
||||
the NDK, and specify it like so:
|
||||
|
||||
./configure --with-ndk-cxx-shared=/path/to/sysroot/libc++_shared.so
|
||||
|
||||
Emacs will then read the ``Android.mk'' file in each directory, and
|
||||
automatically build and use those modules.
|
||||
|
||||
When building for Intel systems, some ``ndk-build'' modules require
|
||||
the Netwide Assembler, usually installed under ``nasm'', to be present
|
||||
on the system that is building Emacs.
|
||||
|
||||
Google, Inc. has adapted many common Emacs dependencies to use the
|
||||
`ndk-build' system. Here is a non-exhaustive list of what is known to
|
||||
work, along with what has to be patched to make them work:
|
||||
|
||||
libpng - https://android.googlesource.com/platform/external/libpng
|
||||
libwebp - https://android.googlesource.com/platform/external/webp
|
||||
(You must apply the patch at the end of this file for the resulting
|
||||
binary to work on armv7 devices.)
|
||||
giflib - https://android.googlesource.com/platform/external/giflib
|
||||
(You must add LOCAL_EXPORT_CFLAGS := -I$(LOCAL_PATH) before
|
||||
its Android.mk includes $(BUILD_STATIC_LIBRARY))
|
||||
libjpeg-turbo - https://android.googlesource.com/platform/external/libjpeg-turbo
|
||||
(You must add LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) before
|
||||
its Android.mk includes $(BUILD_SHARED_LIBRARY))
|
||||
libxml2 - https://android.googlesource.com/platform/external/libxml2/
|
||||
(You must also place the dependency icu4c in ``--with-ndk-path'',
|
||||
and apply the patch at the end of this file.)
|
||||
icu4c - https://android.googlesource.com/platform/external/icu/
|
||||
(You must apply the patch at the end of this file.)
|
||||
sqlite3 - https://android.googlesource.com/platform/external/sqlite/
|
||||
(You must apply the patch at the end of this file, and add the `dist'
|
||||
directory to ``--with-ndk-path''.)
|
||||
libselinux - https://android.googlesource.com/platform/external/libselinux
|
||||
(You must apply the patches at the end of the file, and obtain
|
||||
the following three dependencies.)
|
||||
libpackagelistparser
|
||||
https://android.googlesource.com/platform/system/core/+/refs/heads/nougat-mr1-dev/libpackagelistparser/
|
||||
libpcre - https://android.googlesource.com/platform/external/pcre
|
||||
libcrypto - https://android.googlesource.com/platform/external/boringssl
|
||||
(You must apply the patch at the end of this file when building for
|
||||
ARM systems.)
|
||||
|
||||
Many of these dependencies have been migrated over to the
|
||||
``Android.bp'' build system now used to build Android itself.
|
||||
However, the old ``Android.mk'' Makefiles are still present in older
|
||||
branches, and can be easily adapte to newer versions.
|
||||
|
||||
In addition, some Emacs dependencies provide `ndk-build' support
|
||||
themselves:
|
||||
|
||||
libjansson - https://github.com/akheron/jansson
|
||||
(You must add LOCAL_EXPORT_INCLUDES := $(LOCAL_C_INCLUDES) before
|
||||
its Android.mk includes $(BUILD_SHARED_LIBRARY), then copy
|
||||
android/jansson_config.h to android/jansson_private_config.h.)
|
||||
|
||||
Emacs developers have ported the following dependencies to ARM Android
|
||||
systems:
|
||||
|
||||
gnutls, gmp - https://sourceforge.net/projects/android-ports-for-gnu-emacs
|
||||
(Please see the section GNUTLS near the end of this file.)
|
||||
libtiff - https://sourceforge.net/projects/android-ports-for-gnu-emacs
|
||||
(Extract and point ``--with-ndk-path'' to tiff-4.5.0-emacs.tar.gz.)
|
||||
tree-sitter - https://sourceforge.net/projects/android-ports-for-gnu-emacs
|
||||
(Please see the section TREE-SITTER near the end of this file.)
|
||||
harfbuzz - https://sourceforge.net/projects/android-ports-for-gnu-emacs
|
||||
(Please see the section HARFBUZZ near the end of this file.)
|
||||
|
||||
And other developers have ported the following dependencies to Android
|
||||
systems:
|
||||
|
||||
ImageMagick, lcms2 - https://github.com/MolotovCherry/Android-ImageMagick7
|
||||
(Please see the section IMAGEMAGICK near the end of this file.)
|
||||
|
||||
We anticipate that most untested non-trivial ndk-build dependencies
|
||||
will need adjustments in Emacs to work, as the Emacs build system
|
||||
which emulates ndk-build is in an extremely early state.
|
||||
|
||||
|
||||
GNUTLS
|
||||
|
||||
Modified copies of GnuTLS and its dependencies (such as libgmp,
|
||||
libtasn1, p11-kit) which can be built with the ndk-build system can be
|
||||
found at https://sourceforge.net/projects/android-ports-for-gnu-emacs.
|
||||
|
||||
They have only been tested on arm64 Android systems running Android
|
||||
5.0 or later, and armv7l systems running Android 13 or later, so your
|
||||
mileage may vary, especially if you are trying to build Emacs for
|
||||
another kind of machine.
|
||||
|
||||
To build Emacs with GnuTLS, you must unpack each of the following tar
|
||||
archives in that site:
|
||||
|
||||
gmp-6.2.1-emacs.tgz
|
||||
gnutls-3.7.8-emacs.tar.gz
|
||||
libtasn1-4.19.0-emacs.tar.gz
|
||||
p11-kit-0.24.1-emacs.tar.gz
|
||||
nettle-3.8-emacs.tar.gz
|
||||
|
||||
and add the resulting folders to ``--with-ndk-path''. Note that you
|
||||
should not try to build these packages separately using any
|
||||
`configure' script or Makefiles inside.
|
||||
|
||||
|
||||
TREE-SITTER
|
||||
|
||||
A copy of tree-sitter modified to build with the ndk-build system can
|
||||
also be found that URL. To build Emacs with tree-sitter, you must
|
||||
unpack the following tar archive in that site:
|
||||
|
||||
tree-sitter-0.20.7-emacs.tar.gz
|
||||
|
||||
and add the resulting folder to ``--with-ndk-build''.
|
||||
|
||||
|
||||
HARFBUZZ
|
||||
|
||||
A copy of HarfBuzz modified to build with the ndk-build system can
|
||||
also be found at that URL. To build Emacs with HarfBuzz, you must
|
||||
unpack the following tar archive in that site:
|
||||
|
||||
harfbuzz-7.1.0-emacs.tar.gz
|
||||
|
||||
and add the resulting folder to ``--with-ndk-build''.
|
||||
|
||||
|
||||
IMAGEMAGICK
|
||||
|
||||
There is a third party port of ImageMagick to Android. Unfortunately,
|
||||
the port also uses its own patched versions of libpng, libjpeg,
|
||||
libtiff and libwebp, which conflict with those used by Emacs. Its
|
||||
Makefiles were also written for MS Windows, so you must also apply the
|
||||
patch at the end of this file.
|
||||
|
||||
|
||||
|
||||
PATCH FOR LIBXML2
|
||||
|
||||
This patch must be applied to the Android.mk in Google's version of
|
||||
libxml2 before it can be built for Emacs. In addition, you must also
|
||||
revert the commit `edb5870767fed8712a9b77ef34097209b61ab2db'.
|
||||
|
||||
diff --git a/Android.mk b/Android.mk
|
||||
index 07c7b372..24f67e49 100644
|
||||
--- a/Android.mk
|
||||
+++ b/Android.mk
|
||||
@@ -80,6 +80,7 @@ LOCAL_SHARED_LIBRARIES := libicuuc
|
||||
LOCAL_MODULE:= libxml2
|
||||
LOCAL_CLANG := true
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
|
||||
+LOCAL_EXPORT_C_INCLUDES += $(LOCAL_PATH)
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
# For the host
|
||||
@@ -94,3 +95,5 @@ LOCAL_MODULE := libxml2
|
||||
LOCAL_CLANG := true
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
|
||||
include $(BUILD_HOST_STATIC_LIBRARY)
|
||||
+
|
||||
+$(call import-module,libicuuc)
|
||||
|
||||
PATCH FOR ICU
|
||||
|
||||
This patch must be applied to icu4j/Android.mk in Google's version of
|
||||
icu before it can be built for Emacs.
|
||||
|
||||
diff --git a/icu4j/Android.mk b/icu4j/Android.mk
|
||||
index d1ab3d5..69eff81 100644
|
||||
--- a/icu4j/Android.mk
|
||||
+++ b/icu4j/Android.mk
|
||||
@@ -69,7 +69,7 @@ include $(BUILD_STATIC_JAVA_LIBRARY)
|
||||
# Path to the ICU4C data files in the Android device file system:
|
||||
icu4c_data := /system/usr/icu
|
||||
icu4j_config_root := $(LOCAL_PATH)/main/classes/core/src
|
||||
-include external/icu/icu4j/adjust_icudt_path.mk
|
||||
+include $(LOCAL_PATH)/adjust_icudt_path.mk
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_SRC_FILES := $(icu4j_src_files)
|
||||
|
||||
diff --git a/icu4c/source/common/Android.mk b/icu4c/source/common/Android.mk
|
||||
index 8e5f757..44bb130 100644
|
||||
--- a/icu4c/source/common/Android.mk
|
||||
+++ b/icu4c/source/common/Android.mk
|
||||
@@ -231,7 +231,7 @@ include $(CLEAR_VARS)
|
||||
LOCAL_SRC_FILES += $(src_files)
|
||||
LOCAL_C_INCLUDES += $(c_includes) $(optional_android_logging_includes)
|
||||
LOCAL_CFLAGS += $(local_cflags) -DPIC -fPIC
|
||||
-LOCAL_SHARED_LIBRARIES += libdl $(optional_android_logging_libraries)
|
||||
+LOCAL_SHARED_LIBRARIES += libdl libstdc++ $(optional_android_logging_libraries)
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_MODULE := libicuuc
|
||||
LOCAL_RTTI_FLAG := -frtti
|
||||
|
||||
PATCH FOR SQLITE3
|
||||
|
||||
diff --git a/dist/Android.mk b/dist/Android.mk
|
||||
index bf277d2..36734d9 100644
|
||||
--- a/dist/Android.mk
|
||||
+++ b/dist/Android.mk
|
||||
@@ -141,6 +141,7 @@ include $(BUILD_HOST_EXECUTABLE)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_SRC_FILES := $(common_src_files)
|
||||
LOCAL_CFLAGS += $(minimal_sqlite_flags)
|
||||
+LOCAL_EXPORT_C_INCLUDES += $(LOCAL_PATH)
|
||||
LOCAL_MODULE:= libsqlite_static_minimal
|
||||
LOCAL_SDK_VERSION := 23
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
diff --git a/dist/sqlite3.c b/dist/sqlite3.c
|
||||
index b0536a4..8fa1ee9 100644
|
||||
--- a/dist/sqlite3.c
|
||||
+++ b/dist/sqlite3.c
|
||||
@@ -26474,7 +26474,7 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
|
||||
*/
|
||||
#if !defined(HAVE_POSIX_FALLOCATE) \
|
||||
&& (_XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L)
|
||||
-# define HAVE_POSIX_FALLOCATE 1
|
||||
+/* # define HAVE_POSIX_FALLOCATE 1 */
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
||||
PATCH FOR WEBP
|
||||
|
||||
diff --git a/Android.mk b/Android.mk
|
||||
index c7bcb0f5..d4da1704 100644
|
||||
--- a/Android.mk
|
||||
+++ b/Android.mk
|
||||
@@ -28,9 +28,10 @@ ifneq ($(findstring armeabi-v7a, $(TARGET_ARCH_ABI)),)
|
||||
# Setting LOCAL_ARM_NEON will enable -mfpu=neon which may cause illegal
|
||||
# instructions to be generated for armv7a code. Instead target the neon code
|
||||
# specifically.
|
||||
- NEON := c.neon
|
||||
- USE_CPUFEATURES := yes
|
||||
- WEBP_CFLAGS += -DHAVE_CPU_FEATURES_H
|
||||
+ # NEON := c.neon
|
||||
+ # USE_CPUFEATURES := yes
|
||||
+ # WEBP_CFLAGS += -DHAVE_CPU_FEATURES_H
|
||||
+ NEON := c
|
||||
else
|
||||
NEON := c
|
||||
endif
|
||||
|
||||
PATCHES FOR SELINUX
|
||||
|
||||
diff --git a/Android.mk b/Android.mk
|
||||
index 659232e..1e64fd6 100644
|
||||
--- a/Android.mk
|
||||
+++ b/Android.mk
|
||||
@@ -116,3 +116,7 @@ LOCAL_STATIC_LIBRARIES := libselinux
|
||||
LOCAL_WHOLE_STATIC_LIBRARIES := libpcre
|
||||
LOCAL_C_INCLUDES := external/pcre
|
||||
include $(BUILD_HOST_EXECUTABLE)
|
||||
+
|
||||
+$(call import-module,libpcre)
|
||||
+$(call import-module,libpackagelistparser)
|
||||
+$(call import-module,libcrypto)
|
||||
|
||||
diff --git a/src/android.c b/src/android.c
|
||||
index 5206a9f..b351ffc 100644
|
||||
--- a/src/android.c
|
||||
+++ b/src/android.c
|
||||
@@ -21,8 +21,7 @@
|
||||
#include <selinux/label.h>
|
||||
#include <selinux/avc.h>
|
||||
#include <openssl/sha.h>
|
||||
-#include <private/android_filesystem_config.h>
|
||||
-#include <log/log.h>
|
||||
+#include <android/log.h>
|
||||
#include "policy.h"
|
||||
#include "callbacks.h"
|
||||
#include "selinux_internal.h"
|
||||
@@ -686,6 +685,7 @@ static int seapp_context_lookup(enum seapp_kind kind,
|
||||
seinfo = parsedseinfo;
|
||||
}
|
||||
|
||||
+#if 0
|
||||
userid = uid / AID_USER;
|
||||
isOwner = (userid == 0);
|
||||
appid = uid % AID_USER;
|
||||
@@ -702,9 +702,13 @@ static int seapp_context_lookup(enum seapp_kind kind,
|
||||
username = "_app";
|
||||
appid -= AID_APP;
|
||||
} else {
|
||||
+#endif
|
||||
username = "_isolated";
|
||||
+ appid = 0;
|
||||
+#if 0
|
||||
appid -= AID_ISOLATED_START;
|
||||
}
|
||||
+#endif
|
||||
|
||||
if (appid >= CAT_MAPPING_MAX_ID || userid >= CAT_MAPPING_MAX_ID)
|
||||
goto err;
|
||||
@@ -1662,8 +1666,10 @@ int selinux_log_callback(int type, const char *fmt, ...)
|
||||
|
||||
va_start(ap, fmt);
|
||||
if (vasprintf(&strp, fmt, ap) != -1) {
|
||||
+#if 0
|
||||
LOG_PRI(priority, "SELinux", "%s", strp);
|
||||
LOG_EVENT_STRING(AUDITD_LOG_TAG, strp);
|
||||
+#endif
|
||||
free(strp);
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
PATCH FOR BORINGSSL
|
||||
|
||||
diff --git a/Android.mk b/Android.mk
|
||||
index 3e3ef2a..277d4a9 100644
|
||||
--- a/Android.mk
|
||||
+++ b/Android.mk
|
||||
@@ -27,7 +27,9 @@ LOCAL_MODULE := libcrypto
|
||||
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/src/include
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk $(LOCAL_PATH)/crypto-sources.mk
|
||||
LOCAL_CFLAGS += -fvisibility=hidden -DBORINGSSL_SHARED_LIBRARY -DBORINGSSL_IMPLEMENTATION -DOPENSSL_SMALL -Wno-unused-parameter
|
||||
+LOCAL_CFLAGS_arm = -DOPENSSL_STATIC_ARMCAP -DOPENSSL_NO_ASM
|
||||
LOCAL_SDK_VERSION := 9
|
||||
+LOCAL_LDFLAGS = --no-undefined
|
||||
# sha256-armv4.S does not compile with clang.
|
||||
LOCAL_CLANG_ASFLAGS_arm += -no-integrated-as
|
||||
LOCAL_CLANG_ASFLAGS_arm64 += -march=armv8-a+crypto
|
||||
diff --git a/sources.mk b/sources.mk
|
||||
index e82f3d5..be3a3c4 100644
|
||||
--- a/sources.mk
|
||||
+++ b/sources.mk
|
||||
@@ -337,20 +337,20 @@ linux_aarch64_sources := \
|
||||
linux-aarch64/crypto/sha/sha256-armv8.S\
|
||||
linux-aarch64/crypto/sha/sha512-armv8.S\
|
||||
|
||||
-linux_arm_sources := \
|
||||
- linux-arm/crypto/aes/aes-armv4.S\
|
||||
- linux-arm/crypto/aes/aesv8-armx32.S\
|
||||
- linux-arm/crypto/aes/bsaes-armv7.S\
|
||||
- linux-arm/crypto/bn/armv4-mont.S\
|
||||
- linux-arm/crypto/modes/ghash-armv4.S\
|
||||
- linux-arm/crypto/modes/ghashv8-armx32.S\
|
||||
- linux-arm/crypto/sha/sha1-armv4-large.S\
|
||||
- linux-arm/crypto/sha/sha256-armv4.S\
|
||||
- linux-arm/crypto/sha/sha512-armv4.S\
|
||||
- src/crypto/chacha/chacha_vec_arm.S\
|
||||
- src/crypto/cpu-arm-asm.S\
|
||||
- src/crypto/curve25519/asm/x25519-asm-arm.S\
|
||||
- src/crypto/poly1305/poly1305_arm_asm.S\
|
||||
+# linux_arm_sources := \
|
||||
+# linux-arm/crypto/aes/aes-armv4.S\
|
||||
+# linux-arm/crypto/aes/aesv8-armx32.S\
|
||||
+# linux-arm/crypto/aes/bsaes-armv7.S\
|
||||
+# linux-arm/crypto/bn/armv4-mont.S\
|
||||
+# linux-arm/crypto/modes/ghash-armv4.S\
|
||||
+# linux-arm/crypto/modes/ghashv8-armx32.S\
|
||||
+# linux-arm/crypto/sha/sha1-armv4-large.S\
|
||||
+# linux-arm/crypto/sha/sha256-armv4.S\
|
||||
+# linux-arm/crypto/sha/sha512-armv4.S\
|
||||
+# src/crypto/chacha/chacha_vec_arm.S\
|
||||
+# src/crypto/cpu-arm-asm.S\
|
||||
+# src/crypto/curve25519/asm/x25519-asm-arm.S\
|
||||
+# src/crypto/poly1305/poly1305_arm_asm.S\
|
||||
|
||||
linux_x86_sources := \
|
||||
linux-x86/crypto/aes/aes-586.S\
|
||||
|
||||
PATCH FOR IMAGEMAGICK
|
||||
|
||||
diff --git a/Android.mk b/Android.mk
|
||||
index 5ab6699..4441417 100644
|
||||
--- a/Android.mk
|
||||
+++ b/Android.mk
|
||||
@@ -52,6 +52,20 @@ LZMA_LIB_PATH := $(LOCAL_PATH)/xz-5.2.4
|
||||
BZLIB_LIB_PATH := $(LOCAL_PATH)/bzip-1.0.8
|
||||
LCMS_LIB_PATH := $(LOCAL_PATH)/liblcms2-2.9
|
||||
|
||||
+LIBBZ2_ENABLED := true
|
||||
+LIBFFTW_ENABLED := true
|
||||
+LIBFREETYPE2_ENABLED := true
|
||||
+LIBJPEG_TURBO_ENABLED := true
|
||||
+LIBLZMA_ENABLED := true
|
||||
+LIBOPENJPEG_ENABLED := true
|
||||
+LIBPNG_ENABLED := true
|
||||
+LIBTIFF_ENABLED := true
|
||||
+LIBWEBP_ENABLED := true
|
||||
+LIBXML2_ENABLED := true
|
||||
+LIBZLIB_ENABLED := true
|
||||
+LIBLCMS2_ENABLED := true
|
||||
+BUILD_MAGICKWAND := true
|
||||
+
|
||||
#-------------------------------------------------------------
|
||||
# Include all modules
|
||||
#-------------------------------------------------------------
|
||||
@@ -68,6 +82,9 @@ include $(MAKE_PATH)/libjpeg-turbo.mk
|
||||
# libopenjpeg
|
||||
include $(MAKE_PATH)/libopenjpeg.mk
|
||||
|
||||
+# libwebp
|
||||
+include $(MAKE_PATH)/libwebp.mk
|
||||
+
|
||||
# libtiff
|
||||
include $(MAKE_PATH)/libtiff.mk
|
||||
|
||||
@@ -77,9 +94,6 @@ include $(MAKE_PATH)/libpng.mk
|
||||
# libfreetype2
|
||||
include $(MAKE_PATH)/libfreetype2.mk
|
||||
|
||||
-# libwebp
|
||||
-include $(MAKE_PATH)/libwebp.mk
|
||||
-
|
||||
# libfftw
|
||||
include $(MAKE_PATH)/libfftw.mk
|
||||
|
||||
diff --git a/libjpeg-turbo-2.0.2/jconfig.h b/libjpeg-turbo-2.0.2/jconfig.h
|
||||
index 47d14c9..5c6f8ee 100644
|
||||
--- a/libjpeg-turbo-2.0.2/jconfig.h
|
||||
+++ b/libjpeg-turbo-2.0.2/jconfig.h
|
||||
@@ -1,57 +1,43 @@
|
||||
-/* autogenerated jconfig.h based on Android.mk var JCONFIG_FLAGS */
|
||||
+/* autogenerated jconfig.h based on Android.mk var JCONFIG_FLAGS */
|
||||
#ifndef JPEG_LIB_VERSION
|
||||
#define JPEG_LIB_VERSION 62
|
||||
#endif
|
||||
-
|
||||
#ifndef LIBJPEG_TURBO_VERSION
|
||||
#define LIBJPEG_TURBO_VERSION 2.0.2
|
||||
#endif
|
||||
-
|
||||
#ifndef LIBJPEG_TURBO_VERSION_NUMBER
|
||||
#define LIBJPEG_TURBO_VERSION_NUMBER 202
|
||||
#endif
|
||||
-
|
||||
#ifndef C_ARITH_CODING_SUPPORTED
|
||||
#define C_ARITH_CODING_SUPPORTED
|
||||
#endif
|
||||
-
|
||||
#ifndef D_ARITH_CODING_SUPPORTED
|
||||
#define D_ARITH_CODING_SUPPORTED
|
||||
#endif
|
||||
-
|
||||
#ifndef MEM_SRCDST_SUPPORTED
|
||||
#define MEM_SRCDST_SUPPORTED
|
||||
#endif
|
||||
-
|
||||
#ifndef WITH_SIMD
|
||||
#define WITH_SIMD
|
||||
#endif
|
||||
-
|
||||
#ifndef BITS_IN_JSAMPLE
|
||||
#define BITS_IN_JSAMPLE 8
|
||||
#endif
|
||||
-
|
||||
#ifndef HAVE_LOCALE_H
|
||||
#define HAVE_LOCALE_H
|
||||
#endif
|
||||
-
|
||||
#ifndef HAVE_STDDEF_H
|
||||
#define HAVE_STDDEF_H
|
||||
#endif
|
||||
-
|
||||
#ifndef HAVE_STDLIB_H
|
||||
#define HAVE_STDLIB_H
|
||||
#endif
|
||||
-
|
||||
#ifndef NEED_SYS_TYPES_H
|
||||
#define NEED_SYS_TYPES_H
|
||||
#endif
|
||||
-
|
||||
#ifndef HAVE_UNSIGNED_CHAR
|
||||
#define HAVE_UNSIGNED_CHAR
|
||||
#endif
|
||||
-
|
||||
#ifndef HAVE_UNSIGNED_SHORT
|
||||
#define HAVE_UNSIGNED_SHORT
|
||||
#endif
|
||||
-
|
||||
diff --git a/libxml2-2.9.9/encoding.c b/libxml2-2.9.9/encoding.c
|
||||
index a3aaf10..60f165b 100644
|
||||
--- a/libxml2-2.9.9/encoding.c
|
||||
+++ b/libxml2-2.9.9/encoding.c
|
||||
@@ -2394,7 +2394,6 @@ xmlCharEncOutput(xmlOutputBufferPtr output, int init)
|
||||
{
|
||||
int ret;
|
||||
size_t written;
|
||||
- size_t writtentot = 0;
|
||||
size_t toconv;
|
||||
int c_in;
|
||||
int c_out;
|
||||
@@ -2451,7 +2450,6 @@ retry:
|
||||
xmlBufContent(in), &c_in);
|
||||
xmlBufShrink(in, c_in);
|
||||
xmlBufAddLen(out, c_out);
|
||||
- writtentot += c_out;
|
||||
if (ret == -1) {
|
||||
if (c_out > 0) {
|
||||
/* Can be a limitation of iconv or uconv */
|
||||
@@ -2536,7 +2534,6 @@ retry:
|
||||
}
|
||||
|
||||
xmlBufAddLen(out, c_out);
|
||||
- writtentot += c_out;
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
@@ -2567,9 +2564,7 @@ xmlCharEncOutFunc(xmlCharEncodingHandler *handler, xmlBufferPtr out,
|
||||
xmlBufferPtr in) {
|
||||
int ret;
|
||||
int written;
|
||||
- int writtentot = 0;
|
||||
int toconv;
|
||||
- int output = 0;
|
||||
|
||||
if (handler == NULL) return(-1);
|
||||
if (out == NULL) return(-1);
|
||||
@@ -2612,7 +2607,6 @@ retry:
|
||||
in->content, &toconv);
|
||||
xmlBufferShrink(in, toconv);
|
||||
out->use += written;
|
||||
- writtentot += written;
|
||||
out->content[out->use] = 0;
|
||||
if (ret == -1) {
|
||||
if (written > 0) {
|
||||
@@ -2622,8 +2616,6 @@ retry:
|
||||
ret = -3;
|
||||
}
|
||||
|
||||
- if (ret >= 0) output += ret;
|
||||
-
|
||||
/*
|
||||
* Attempt to handle error cases
|
||||
*/
|
||||
@@ -2700,7 +2692,6 @@ retry:
|
||||
}
|
||||
|
||||
out->use += written;
|
||||
- writtentot += written;
|
||||
out->content[out->use] = 0;
|
||||
goto retry;
|
||||
}
|
||||
diff --git a/libxml2-2.9.9/xpath.c b/libxml2-2.9.9/xpath.c
|
||||
index 5e3bb9f..505ec82 100644
|
||||
--- a/libxml2-2.9.9/xpath.c
|
||||
+++ b/libxml2-2.9.9/xpath.c
|
||||
@@ -10547,7 +10547,7 @@ xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
|
||||
|
||||
static xmlChar *
|
||||
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
|
||||
- int len = 0, l;
|
||||
+ int l;
|
||||
int c;
|
||||
const xmlChar *cur;
|
||||
xmlChar *ret;
|
||||
@@ -10567,7 +10567,6 @@ xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
|
||||
(c == '_') || (c == ':') ||
|
||||
(IS_COMBINING(c)) ||
|
||||
(IS_EXTENDER(c)))) {
|
||||
- len += l;
|
||||
NEXTL(l);
|
||||
c = CUR_CHAR(l);
|
||||
}
|
||||
diff --git a/make/libicu4c.mk b/make/libicu4c.mk
|
||||
index 21ec121..8b77865 100644
|
||||
--- a/make/libicu4c.mk
|
||||
+++ b/make/libicu4c.mk
|
||||
@@ -250,7 +250,7 @@ LOCAL_MODULE := libicuuc
|
||||
LOCAL_SRC_FILES := $(src_files)
|
||||
|
||||
# when built in android, they require uconfig_local (because of android project), but we don't need this
|
||||
-$(shell > $(ICU_COMMON_PATH)/unicode/uconfig_local.h echo /* Autogenerated stub file to make libicuuc build happy */) \
|
||||
+$(shell > $(ICU_COMMON_PATH)/unicode/uconfig_local.h echo /\* Autogenerated stub file to make libicuuc build happy \*/) \
|
||||
|
||||
ifeq ($(LIBXML2_ENABLED),true)
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
diff --git a/make/libjpeg-turbo.mk b/make/libjpeg-turbo.mk
|
||||
index d39dd41..fdebcf3 100644
|
||||
--- a/make/libjpeg-turbo.mk
|
||||
+++ b/make/libjpeg-turbo.mk
|
||||
@@ -230,30 +230,30 @@ JCONFIG_FLAGS += \
|
||||
HAVE_UNSIGNED_SHORT
|
||||
|
||||
JCONFIGINT_FLAGS += \
|
||||
- BUILD="20190814" \
|
||||
- PACKAGE_NAME="libjpeg-turbo" \
|
||||
- VERSION="2.0.2"
|
||||
+ BUILD=\"20190814\" \
|
||||
+ PACKAGE_NAME=\"libjpeg-turbo\" \
|
||||
+ VERSION=\"2.0.2\"
|
||||
|
||||
# originally defined in jconfigint.h, but the substitution has problems with spaces
|
||||
LOCAL_CFLAGS := \
|
||||
-DINLINE="inline __attribute__((always_inline))"
|
||||
|
||||
# create definition file jconfig.h, needed in order to build
|
||||
-$(shell echo /* autogenerated jconfig.h based on Android.mk var JCONFIG_FLAGS */ > $(JPEG_LIB_PATH)/jconfig.h)
|
||||
+$(shell echo \/\* autogenerated jconfig.h based on Android.mk var JCONFIG_FLAGS \*\/ > $(JPEG_LIB_PATH)/jconfig.h)
|
||||
$(foreach name,$(JCONFIG_FLAGS), \
|
||||
$(if $(findstring =,$(name)), \
|
||||
- $(shell >>$(JPEG_LIB_PATH)/jconfig.h echo #ifndef $(firstword $(subst =, ,$(name)))) \
|
||||
+ $(shell >>$(JPEG_LIB_PATH)/jconfig.h echo \#ifndef $(firstword $(subst =, ,$(name)))) \
|
||||
, \
|
||||
- $(shell >>$(JPEG_LIB_PATH)/jconfig.h echo #ifndef $(name)) \
|
||||
+ $(shell >>$(JPEG_LIB_PATH)/jconfig.h echo \#ifndef $(name)) \
|
||||
) \
|
||||
- $(shell >>$(JPEG_LIB_PATH)/jconfig.h echo #define $(subst =, ,$(name))) \
|
||||
- $(shell >>$(JPEG_LIB_PATH)/jconfig.h echo #endif) \
|
||||
+ $(shell >>$(JPEG_LIB_PATH)/jconfig.h echo \#define $(subst =, ,$(name))) \
|
||||
+ $(shell >>$(JPEG_LIB_PATH)/jconfig.h echo \#endif) \
|
||||
$(shell >> $(JPEG_LIB_PATH)/jconfig.h echo.) \
|
||||
)
|
||||
|
||||
# create definition file jconfigint.h, needed in order to build
|
||||
-$(shell >$(JPEG_LIB_PATH)/jconfigint.h echo /* autogenerated jconfigint.h based on Android.mk vars JCONFIGINT_FLAGS */)
|
||||
-$(foreach name,$(JCONFIGINT_FLAGS),$(shell >>$(JPEG_LIB_PATH)/jconfigint.h echo #define $(subst =, ,$(name))))
|
||||
+$(shell >$(JPEG_LIB_PATH)/jconfigint.h echo /\* autogenerated jconfigint.h based on Android.mk vars JCONFIGINT_FLAGS \*/)
|
||||
+$(foreach name,$(JCONFIGINT_FLAGS),$(shell >>$(JPEG_LIB_PATH)/jconfigint.h echo \#define $(subst =, ,$(name))))
|
||||
|
||||
ifeq ($(LIBJPEG_TURBO_ENABLED),true)
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
diff --git a/make/liblcms2.mk b/make/liblcms2.mk
|
||||
index e1fd3b9..29ca791 100644
|
||||
--- a/make/liblcms2.mk
|
||||
+++ b/make/liblcms2.mk
|
||||
@@ -10,6 +10,10 @@ LOCAL_C_INCLUDES := \
|
||||
$(LCMS_LIB_PATH)/include \
|
||||
$(LCMS_LIB_PATH)/src
|
||||
|
||||
+LOCAL_EXPORT_C_INCLUDES := \
|
||||
+ $(LCMS_LIB_PATH) \
|
||||
+ $(LCMS_LIB_PATH)/include \
|
||||
+ $(LCMS_LIB_PATH)/src
|
||||
|
||||
LOCAL_CFLAGS := \
|
||||
-DHAVE_FUNC_ATTRIBUTE_VISIBILITY=1 \
|
||||
diff --git a/make/libmagick++-7.mk b/make/libmagick++-7.mk
|
||||
index 5352ccb..929396d 100644
|
||||
--- a/make/libmagick++-7.mk
|
||||
+++ b/make/libmagick++-7.mk
|
||||
@@ -12,7 +12,7 @@ LOCAL_C_INCLUDES := \
|
||||
|
||||
ifneq ($(STATIC_BUILD),true)
|
||||
LOCAL_LDFLAGS += -fexceptions
|
||||
- LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog -lz
|
||||
+ LOCAL_LDLIBS := -llog -lz
|
||||
endif
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
diff --git a/make/libmagickcore-7.mk b/make/libmagickcore-7.mk
|
||||
index 81293b2..d51fced 100644
|
||||
--- a/make/libmagickcore-7.mk
|
||||
+++ b/make/libmagickcore-7.mk
|
||||
@@ -25,6 +25,7 @@ else ifeq ($(TARGET_ARCH_ABI),x86_64)
|
||||
|
||||
endif
|
||||
|
||||
+LOCAL_EXPORT_C_INCLUDES += $(IMAGE_MAGICK)
|
||||
|
||||
LOCAL_C_INCLUDES += \
|
||||
$(IMAGE_MAGICK) \
|
||||
@@ -45,10 +46,9 @@ LOCAL_C_INCLUDES += \
|
||||
$(BZLIB_LIB_PATH) \
|
||||
$(LCMS_LIB_PATH)/include
|
||||
|
||||
-
|
||||
ifneq ($(STATIC_BUILD),true)
|
||||
# ignored in static library builds
|
||||
- LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog -lz
|
||||
+ LOCAL_LDLIBS := -llog -lz
|
||||
endif
|
||||
|
||||
|
||||
diff --git a/make/libmagickwand-7.mk b/make/libmagickwand-7.mk
|
||||
index 7be2fb6..0bbcca5 100644
|
||||
--- a/make/libmagickwand-7.mk
|
||||
+++ b/make/libmagickwand-7.mk
|
||||
@@ -14,7 +14,7 @@ LOCAL_C_INCLUDES := \
|
||||
|
||||
# always ignored in static builds
|
||||
ifneq ($(STATIC_BUILD),true)
|
||||
- LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog -lz
|
||||
+ LOCAL_LDLIBS := -llog -lz
|
||||
endif
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
@@ -54,6 +54,29 @@ ifeq ($(OPENCL_BUILD),true)
|
||||
LOCAL_SHARED_LIBRARIES += libopencl
|
||||
endif
|
||||
|
||||
+LOCAL_SHARED_LIBRARIES += libstdc++
|
||||
+
|
||||
+ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
|
||||
+ LOCAL_EXPORT_C_INCLUDES += $(IMAGE_MAGICK)/configs/arm64
|
||||
+ LOCAL_C_INCLUDES += $(IMAGE_MAGICK)/configs/arm64
|
||||
+else ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
|
||||
+ LOCAL_EXPORT_C_INCLUDES += $(IMAGE_MAGICK)/configs/arm
|
||||
+ LOCAL_C_INCLUDES += $(IMAGE_MAGICK)/configs/arm
|
||||
+else ifeq ($(TARGET_ARCH_ABI),x86)
|
||||
+ LOCAL_EXPORT_C_INCLUDES += $(IMAGE_MAGICK)/configs/x86
|
||||
+ LOCAL_C_INCLUDES += $(IMAGE_MAGICK)/configs/x86
|
||||
+else ifeq ($(TARGET_ARCH_ABI),x86_64)
|
||||
+ LOCAL_EXPORT_C_INCLUDES += $(IMAGE_MAGICK)/configs/x86-64
|
||||
+ LOCAL_C_INCLUDES += $(IMAGE_MAGICK)/configs/x86-64
|
||||
+
|
||||
+ ifneq ($(STATIC_BUILD),true)
|
||||
+ LOCAL_LDFLAGS += -latomic
|
||||
+ endif
|
||||
+
|
||||
+endif
|
||||
+
|
||||
+LOCAL_EXPORT_C_INCLUDES += $(IMAGE_MAGICK)
|
||||
+
|
||||
ifeq ($(BUILD_MAGICKWAND),true)
|
||||
ifeq ($(STATIC_BUILD),true)
|
||||
LOCAL_STATIC_LIBRARIES := \
|
||||
diff --git a/make/libpng.mk b/make/libpng.mk
|
||||
index 24fb8ac..dda05fd 100644
|
||||
--- a/make/libpng.mk
|
||||
+++ b/make/libpng.mk
|
||||
@@ -30,6 +30,7 @@ ifeq ($(TARGET_ARCH_ABI), arm64-v8a)
|
||||
endif # TARGET_ARCH_ABI == arm64-v8a
|
||||
|
||||
|
||||
+LOCAL_EXPORT_C_INCLUDES := $(PNG_LIB_PATH)
|
||||
LOCAL_C_INCLUDES := $(PNG_LIB_PATH)
|
||||
|
||||
LOCAL_SRC_FILES += \
|
||||
diff --git a/make/libtiff.mk b/make/libtiff.mk
|
||||
index ca43f25..2b17508 100644
|
||||
--- a/make/libtiff.mk
|
||||
+++ b/make/libtiff.mk
|
||||
@@ -12,6 +12,9 @@ LOCAL_C_INCLUDES := \
|
||||
$(LZMA_LIB_PATH)/liblzma/api \
|
||||
$(WEBP_LIB_PATH)/src
|
||||
|
||||
+LOCAL_EXPORT_C_INCLUDES := \
|
||||
+ $(TIFF_LIB_PATH)
|
||||
+
|
||||
ifeq ($(LIBLZMA_ENABLED),true)
|
||||
LOCAL_CFLAGS += -DLZMA_SUPPORT=1
|
||||
endif
|
||||
diff --git a/make/magick.mk b/make/magick.mk
|
||||
index 3ba4b1d..5471608 100644
|
||||
--- a/make/magick.mk
|
||||
+++ b/make/magick.mk
|
||||
@@ -18,7 +18,7 @@ LOCAL_C_INCLUDES := \
|
||||
$(FREETYPE_LIB_PATH)/include
|
||||
|
||||
|
||||
-LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog -lz
|
||||
+LOCAL_LDLIBS := -llog -lz
|
||||
LOCAL_SRC_FILES := \
|
||||
$(IMAGE_MAGICK)/utilities/magick.c \
|
||||
|
||||
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
337
java/Makefile.in
Normal file
337
java/Makefile.in
Normal file
|
@ -0,0 +1,337 @@
|
|||
### @configure_input@
|
||||
|
||||
# Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU Emacs.
|
||||
|
||||
# GNU Emacs is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# GNU Emacs is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
builddir = @builddir@
|
||||
version = @version@
|
||||
|
||||
# Don't install movemail if mailutils are to be used.
|
||||
emacs_use_mailutils = @emacs_use_mailutils@
|
||||
|
||||
# This is the host lib-src and lib, not the cross compiler's lib-src.
|
||||
libsrc = ../lib-src
|
||||
EXEEXT = @EXEEXT@
|
||||
|
||||
-include ${top_builddir}/src/verbose.mk
|
||||
|
||||
SHELL = @SHELL@
|
||||
JAVAC = @JAVAC@
|
||||
AAPT = @AAPT@
|
||||
D8 = @D8@
|
||||
ZIPALIGN = @ZIPALIGN@
|
||||
JARSIGNER = @JARSIGNER@
|
||||
APKSIGNER = @APKSIGNER@
|
||||
JARSIGNER_FLAGS =
|
||||
ANDROID_JAR = @ANDROID_JAR@
|
||||
ANDROID_ABI = @ANDROID_ABI@
|
||||
ANDROID_SDK_18_OR_EARLIER = @ANDROID_SDK_18_OR_EARLIER@
|
||||
ANDROID_SDK_8_OR_EARLIER = @ANDROID_SDK_8_OR_EARLIER@
|
||||
WARN_JAVAFLAGS = @WARN_JAVAFLAGS@
|
||||
JAVAFLAGS = $(WARN_JAVAFLAGS) -classpath "$(ANDROID_JAR):$(srcdir)"
|
||||
FIND_DELETE = @FIND_DELETE@
|
||||
|
||||
# Android 4.3 and earlier require Emacs to be signed with a different
|
||||
# digital signature algorithm.
|
||||
|
||||
ifneq (,$(ANDROID_SDK_18_OR_EARLIER))
|
||||
JARSIGNER_FLAGS = -sigalg MD5withRSA -digestalg SHA1
|
||||
else
|
||||
JARSIGNER_FLAGS =
|
||||
endif
|
||||
|
||||
# When building Emacs for Android 2.2, assets must not be compressed.
|
||||
# Otherwise, the asset manager fails to extract files larger than 1
|
||||
# MB.
|
||||
|
||||
ifneq (,$(ANDROID_SDK_8_OR_EARLIER))
|
||||
AAPT_ASSET_ARGS = -0 ""
|
||||
else
|
||||
AAPT_ASSET_ARGS =
|
||||
endif
|
||||
|
||||
SIGN_EMACS = -keystore $(srcdir)/emacs.keystore -storepass \
|
||||
emacs1 $(JARSIGNER_FLAGS)
|
||||
SIGN_EMACS_V2 = sign --v2-signing-enabled --ks \
|
||||
$(srcdir)/emacs.keystore -debuggable-apk-permitted \
|
||||
--ks-pass pass:emacs1
|
||||
|
||||
JAVA_FILES := $(wildcard $(srcdir)/org/gnu/emacs/*.java)
|
||||
RESOURCE_FILES := $(foreach file,$(wildcard $(srcdir)/res/*), \
|
||||
$(wildcard $(file)/*))
|
||||
|
||||
# R.java is a file generated by the `aapt' utility containing
|
||||
# constants that can then be used to locate ``resource identifiers''.
|
||||
# It is not a regular file and should not be compiled as Java source
|
||||
# code. Instead, it is automatically included by the Java compiler.
|
||||
RESOURCE_FILE := $(srcdir)/org/gnu/emacs/R.java
|
||||
|
||||
# CLASS_FILES is what should actually be built and included in the
|
||||
# resulting Emacs executable. The Java compiler might generate more
|
||||
# than one class file for each source file, so this only serves as a
|
||||
# list of dependencies for Make.
|
||||
CLASS_FILES := $(foreach file,$(JAVA_FILES),$(basename $(file)).class)
|
||||
|
||||
# Remove RESOURCE_FILE from JAVA_FILES, if it is already present.
|
||||
JAVA_FILES := $(filter-out $(RESOURCE_FILE),$(JAVA_FILES))
|
||||
|
||||
# Compute the name for the Emacs application package. This should be:
|
||||
# emacs-<version>-<min-sdk>-<abi>.apk
|
||||
|
||||
ANDROID_MIN_SDK := @ANDROID_MIN_SDK@
|
||||
APK_NAME := emacs-$(version)-$(ANDROID_MIN_SDK)-$(ANDROID_ABI).apk
|
||||
|
||||
# How this stuff works.
|
||||
|
||||
# emacs.apk depends on emacs.apk-in, which is simply a ZIP archive
|
||||
# containing the following files:
|
||||
# lib/$(ANDROID_ABI)/libemacs.so
|
||||
# lib/$(ANDROID_ABI)/libandroid-emacs.so
|
||||
# lib/$(ANDROID_ABI)/libctags.so
|
||||
# lib/$(ANDROID_ABI)/libetags.so
|
||||
# lib/$(ANDROID_ABI)/libhexl.so
|
||||
# lib/$(ANDROID_ABI)/libmovemail.so
|
||||
# lib/$(ANDROID_ABI)/librcs2log.so
|
||||
# lib/$(ANDROID_ABI)/libebrowse.so
|
||||
# assets/info/
|
||||
# assets/etc/
|
||||
# assets/lisp/
|
||||
|
||||
.PHONY: emacs.apk-in all
|
||||
all: $(APK_NAME)
|
||||
|
||||
# Binaries to cross-compile.
|
||||
CROSS_SRC_BINS := $(top_builddir)/cross/src/android-emacs
|
||||
CROSS_LIBSRC_BINS := $(top_builddir)/cross/lib-src/ctags \
|
||||
$(top_builddir)/cross/lib-src/hexl \
|
||||
$(top_builddir)/cross/lib-src/ebrowse \
|
||||
$(top_builddir)/cross/lib-src/emacsclient \
|
||||
$(top_builddir)/cross/lib-src/etags
|
||||
CROSS_LIBSRC_BINS_MOVEMAIL := $(top_builddir)/cross/lib-src/movemail
|
||||
CROSS_EXEC_BINS := $(top_builddir)/exec/exec1 $(top_builddir)/exec/loader
|
||||
CROSS_BINS = $(CROSS_SRC_BINS) $(CROSS_LIBSRC_BINS) $(CROSS_EXEC_BINS)
|
||||
|
||||
ifneq ($(emacs_use_mailutils),yes)
|
||||
CROSS_LIBSRC_BINS := $(CROSS_LIBSRC_BINS) $(CROSS_LIBSRC_BINS_MOVEMAIL)
|
||||
endif
|
||||
|
||||
# Libraries to cross-compile.
|
||||
CROSS_LIBS = $(top_builddir)/cross/src/libemacs.so
|
||||
|
||||
# Make sure gnulib is built first!
|
||||
# If not, then the recursive invocations of make below will try to
|
||||
# build gnulib at the same time.
|
||||
CROSS_ARCHIVES = $(top_builddir)/cross/lib/libgnu.a
|
||||
|
||||
# Third party libraries to compile.
|
||||
-include $(top_builddir)/cross/ndk-build/ndk-build.mk
|
||||
|
||||
.PHONY: $(CROSS_BINS) $(CROSS_LIBS) $(CROSS_ARCHIVES)
|
||||
|
||||
# There should only be a single invocation of $(MAKE) -C
|
||||
# $(top_srcdir)/cross for each directory under $(top_srcdir)/cross.
|
||||
$(CROSS_SRC_BINS) $(CROSS_LIBS) &: $(CROSS_ARCHIVES)
|
||||
$(MAKE) -C $(top_builddir)/cross $(foreach file, \
|
||||
$(CROSS_SRC_BINS) \
|
||||
$(CROSS_LIBS), \
|
||||
src/$(notdir $(file)))
|
||||
|
||||
$(CROSS_LIBSRC_BINS) &: $(CROSS_ARCHIVES)
|
||||
$(MAKE) -C $(top_builddir)/cross $(foreach file, \
|
||||
$(CROSS_LIBSRC_BINS), \
|
||||
lib-src/$(notdir $(file)))
|
||||
|
||||
$(CROSS_ARCHIVES):
|
||||
$(MAKE) -C $(top_builddir)/cross lib/libgnu.a
|
||||
|
||||
# These two binaries are helpers used to execute binaries on Android
|
||||
# 10 and later.
|
||||
|
||||
$(CROSS_EXEC_BINS) &:
|
||||
$(MAKE) -C $(top_builddir)/exec $(notdir $(CROSS_EXEC_BINS))
|
||||
|
||||
# This is needed to generate the ``.directory-tree'' file used by the
|
||||
# Android emulations of readdir and faccessat.
|
||||
|
||||
$(libsrc)/asset-directory-tool:
|
||||
$(MAKE) -C $(libsrc) $(notdir $@)
|
||||
|
||||
# install_tmp is a directory used to generate emacs.apk-in.
|
||||
# That is then packaged into $(APK_NAME).
|
||||
# There is no need to depend on NDK_BUILD_SHARED as libemacs.so
|
||||
# does already.
|
||||
|
||||
.PHONY: install_temp install_temp/assets/directory-tree
|
||||
install_temp: $(CROSS_BINS) $(CROSS_LIBS) $(RESOURCE_FILES)
|
||||
$(AM_V_GEN)
|
||||
# Make the working directory for this stuff
|
||||
$(AM_V_SILENT) rm -rf install_temp
|
||||
$(AM_V_SILENT) mkdir -p install_temp/lib/$(ANDROID_ABI)
|
||||
$(AM_V_SILENT) mkdir -p install_temp/assets/etc
|
||||
$(AM_V_SILENT) mkdir -p install_temp/assets/lisp
|
||||
$(AM_V_SILENT) mkdir -p install_temp/assets/info
|
||||
# Install architecture independents to assets/etc and assets/lisp
|
||||
$(AM_V_SILENT) cp -r $(top_srcdir)/lisp install_temp/assets
|
||||
$(AM_V_SILENT) cp -r $(top_srcdir)/etc install_temp/assets
|
||||
$(AM_V_SILENT) cp -r $(top_srcdir)/info install_temp/assets
|
||||
# Replace etc/DOC generated by compiling Emacs for the build machine
|
||||
# with etc/DOC from the cross-compiled Emacs.
|
||||
$(AM_V_SILENT) test -f $(top_builddir)/cross/etc/DOC \
|
||||
&& cp -r $(top_builddir)/cross/etc/DOC \
|
||||
install_temp/assets/etc
|
||||
# Remove undesirable files from those directories.
|
||||
$(AM_V_SILENT) \
|
||||
for subdir in `find install_temp -type d -print`; do \
|
||||
chmod a+rx $${subdir} ; \
|
||||
rm -rf $${subdir}/.gitignore ; \
|
||||
rm -rf $${subdir}/.DS_Store ; \
|
||||
rm -rf $${subdir}/#* ; \
|
||||
rm -rf $${subdir}/.#* ; \
|
||||
rm -rf $${subdir}/*~ ; \
|
||||
rm -rf $${subdir}/*.orig ; \
|
||||
rm -rf $${subdir}/ChangeLog* ; \
|
||||
rm -rf $${subdir}/[mM]akefile*[.-]in ; \
|
||||
rm -rf $${subdir}/Makefile; \
|
||||
done
|
||||
# Generate the directory tree for those directories.
|
||||
# Install architecture dependents to lib/$(ANDROID_ABI). This
|
||||
# perculiar naming scheme is required to make Android preserve these
|
||||
# binaries upon installation.
|
||||
$(AM_V_SILENT) \
|
||||
for file in $(CROSS_BINS); do \
|
||||
if [ -x $$file ]; then \
|
||||
filename=`basename $$file`; \
|
||||
cp -f $$file install_temp/lib/$(ANDROID_ABI)/lib$${filename}.so; \
|
||||
fi \
|
||||
done
|
||||
$(AM_V_SILENT) \
|
||||
for file in $(CROSS_LIBS); do \
|
||||
if [ -x $$file ]; then \
|
||||
cp -f $$file install_temp/lib/$(ANDROID_ABI); \
|
||||
fi \
|
||||
done
|
||||
ifneq ($(NDK_BUILD_SHARED),)
|
||||
$(AM_V_SILENT) cp -f $(NDK_BUILD_SHARED) \
|
||||
install_temp/lib/$(ANDROID_ABI)
|
||||
endif
|
||||
|
||||
install_temp/assets/directory-tree: $(libsrc)/asset-directory-tool \
|
||||
install_temp install_temp/assets/version \
|
||||
install_temp/assets/build_info
|
||||
$(AM_V_GEN) $(libsrc)/asset-directory-tool install_temp/assets \
|
||||
install_temp/assets/directory-tree
|
||||
|
||||
install_temp/assets/version: install_temp
|
||||
$(AM_V_GEN) { (cd $(top_srcdir) \
|
||||
&& git rev-parse HEAD || echo "Unknown") \
|
||||
&& (git rev-parse --abbrev-ref HEAD \
|
||||
|| echo "Unknown") } 2> /dev/null > $@
|
||||
|
||||
install_temp/assets/build_info: install_temp
|
||||
$(AM_V_GEN) { hostname; date +%s; } > $@
|
||||
|
||||
emacs.apk-in: install_temp install_temp/assets/directory-tree \
|
||||
AndroidManifest.xml install_temp/assets/version \
|
||||
install_temp/assets/build_info
|
||||
# Package everything. Specifying the assets on this command line is
|
||||
# necessary for AAssetManager_getNextFileName to work on old versions
|
||||
# of Android. Make sure not to generate R.java, as it's already been
|
||||
# generated.
|
||||
$(AM_V_AAPT) $(AAPT) p -I "$(ANDROID_JAR)" -F $@ \
|
||||
-f -M AndroidManifest.xml $(AAPT_ASSET_ARGS) \
|
||||
-A install_temp/assets \
|
||||
-S $(top_srcdir)/java/res -J install_temp
|
||||
$(AM_V_SILENT) pushd install_temp &> /dev/null; \
|
||||
$(AAPT) add ../$@ `find lib -type f`; \
|
||||
popd &> /dev/null
|
||||
$(AM_V_SILENT) rm -rf install_temp
|
||||
|
||||
# Makefile itself.
|
||||
.PRECIOUS: $(top_srcdir)/config.status Makefile
|
||||
$(top_srcdir)/config.status: $(top_srcdir)/configure.ac $(top_srcdir)/m4/*.m4
|
||||
$(MAKE) -C $(dir $@) $(notdir $@)
|
||||
Makefile: $(top_srcdir)/config.status $(top_srcdir)/java/Makefile.in
|
||||
$(MAKE) -C .. java/$@
|
||||
|
||||
# AndroidManifest.xml:
|
||||
AndroidManifest.xml: $(top_srcdir)/configure.ac $(top_srcdir)/m4/*.m4 \
|
||||
$(srcdir)/AndroidManifest.xml.in
|
||||
pushd ..; ./config.status java/AndroidManifest.xml; popd
|
||||
|
||||
# R.java:
|
||||
$(RESOURCE_FILE): $(RESOURCE_FILES)
|
||||
$(AM_V_GEN) $(AAPT) p -I "$(ANDROID_JAR)" -f \
|
||||
-J $(dir $@) -M AndroidManifest.xml \
|
||||
-S $(top_srcdir)/java/res
|
||||
|
||||
# Make all class files depend on R.java being built.
|
||||
$(CLASS_FILES): $(RESOURCE_FILE)
|
||||
|
||||
.SUFFIXES: .java .class
|
||||
$(CLASS_FILES) &: $(JAVA_FILES)
|
||||
$(AM_V_JAVAC) $(JAVAC) $(JAVAFLAGS) $(JAVA_FILES)
|
||||
$(AM_V_SILENT) touch $(CLASS_FILES)
|
||||
|
||||
# N.B. that find must be called all over again in case javac generated
|
||||
# nested classes.
|
||||
|
||||
classes.dex: $(CLASS_FILES)
|
||||
$(AM_V_D8) $(D8) --classpath $(ANDROID_JAR) \
|
||||
$(subst $$,\$$,$(shell find $(srcdir) -type f \
|
||||
-name *.class)) --output $(builddir)
|
||||
|
||||
# When emacs.keystore expires, regenerate it with:
|
||||
#
|
||||
# keytool -genkey -v -keystore emacs.keystore -alias "Emacs keystore" \
|
||||
# -keyalg RSA -sigalg SHA1withRSA -keysize 2048 -validity 100000
|
||||
|
||||
.PHONY: clean maintainer-clean
|
||||
|
||||
$(APK_NAME): classes.dex emacs.apk-in $(srcdir)/emacs.keystore
|
||||
$(AM_V_GEN)
|
||||
$(AM_V_SILENT) cp -f emacs.apk-in $@.unaligned
|
||||
$(AM_V_SILENT) $(AAPT) add $@.unaligned classes.dex
|
||||
$(AM_V_SILENT) $(JARSIGNER) $(SIGN_EMACS) $@.unaligned "Emacs keystore"
|
||||
$(AM_V_SILENT) $(ZIPALIGN) -f 4 $@.unaligned $@
|
||||
# Signing must happen after alignment!
|
||||
$(AM_V_SILENT) $(APKSIGNER) $(SIGN_EMACS_V2) $@
|
||||
$(AM_V_SILENT) rm -f $@.unaligned *.idsig
|
||||
|
||||
# TAGS generation.
|
||||
|
||||
ETAGS = $(top_builddir)/lib-src/etags
|
||||
|
||||
$(ETAGS): FORCE
|
||||
$(MAKE) -C ../lib-src $(notdir $@)
|
||||
|
||||
tagsfiles = $(JAVA_FILES) $(RESOURCE_FILE)
|
||||
|
||||
.PHONY: tags FORCE
|
||||
tags: TAGS
|
||||
TAGS: $(ETAGS) $(tagsfiles)
|
||||
$(AM_V_GEN) $(ETAGS) $(tagsfiles)
|
||||
|
||||
clean:
|
||||
rm -f *.apk emacs.apk-in *.dex *.unaligned *.class *.idsig
|
||||
rm -rf install-temp $(RESOURCE_FILE) TAGS
|
||||
find . -name '*.class' $(FIND_DELETE)
|
||||
|
||||
maintainer-clean distclean bootstrap-clean: clean
|
||||
rm -f Makefile ndk-build.mk
|
1049
java/README
Normal file
1049
java/README
Normal file
File diff suppressed because it is too large
Load diff
368
java/debug.sh
Executable file
368
java/debug.sh
Executable file
|
@ -0,0 +1,368 @@
|
|||
#!/bin/bash
|
||||
### Run Emacs under GDB or JDB on Android.
|
||||
|
||||
## Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
## This file is part of GNU Emacs.
|
||||
|
||||
## GNU Emacs is free software: you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published by
|
||||
## the Free Software Foundation, either version 3 of the License, or
|
||||
## (at your option) any later version.
|
||||
|
||||
## GNU Emacs is distributed in the hope that it will be useful,
|
||||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
|
||||
## You should have received a copy of the GNU General Public License
|
||||
## along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
set -m
|
||||
oldpwd=`pwd`
|
||||
cd `dirname $0`
|
||||
|
||||
devices=`adb devices | grep device | awk -- '/device\y/ { print $1 }' -`
|
||||
device=
|
||||
progname=$0
|
||||
package=org.gnu.emacs
|
||||
activity=org.gnu.emacs.EmacsActivity
|
||||
gdb_port=5039
|
||||
jdb_port=64013
|
||||
jdb=no
|
||||
attach_existing=no
|
||||
gdbserver=
|
||||
gdb=gdb
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
## This option specifies the serial number of a device to use.
|
||||
"--device" )
|
||||
device="$2"
|
||||
if [ -z device ]; then
|
||||
echo "You must specify an argument to --device"
|
||||
exit 1
|
||||
fi
|
||||
shift
|
||||
;;
|
||||
"--help" )
|
||||
echo "Usage: $progname [options] -- [gdb options]"
|
||||
echo ""
|
||||
echo " --device DEVICE run Emacs on the specified device"
|
||||
echo " --port PORT run the GDB server on a specific port"
|
||||
echo " --jdb-port PORT run the JDB server on a specific port"
|
||||
echo " --jdb run JDB instead of GDB"
|
||||
echo " --gdb use specified GDB binary"
|
||||
echo " --attach-existing attach to an existing process"
|
||||
echo " --gdbserver BINARY upload and use the specified gdbserver binary"
|
||||
echo " --help print this message"
|
||||
echo ""
|
||||
echo "Available devices:"
|
||||
for device in $devices; do
|
||||
echo " " $device
|
||||
done
|
||||
echo ""
|
||||
exit 0
|
||||
;;
|
||||
"--jdb" )
|
||||
jdb=yes
|
||||
;;
|
||||
"--gdb" )
|
||||
shift
|
||||
gdb=$1
|
||||
;;
|
||||
"--gdbserver" )
|
||||
shift
|
||||
gdbserver=$1
|
||||
;;
|
||||
"--port" )
|
||||
shift
|
||||
gdb_port=$1
|
||||
;;
|
||||
"--jdb-port" )
|
||||
shift
|
||||
jdb_port=$1
|
||||
;;
|
||||
"--attach-existing" )
|
||||
attach_existing=yes
|
||||
;;
|
||||
"--" )
|
||||
shift
|
||||
gdbargs=$@
|
||||
break;
|
||||
;;
|
||||
* )
|
||||
echo "$progname: Unrecognized argument $1"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [ -z "$devices" ]; then
|
||||
echo "No devices are available."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z $device ]; then
|
||||
device=$devices
|
||||
fi
|
||||
|
||||
if [ `wc -w <<< "$devices"` -gt 1 ] && [ -z device ]; then
|
||||
echo "Multiple devices are available. Please pick one using"
|
||||
echo "--device and try again."
|
||||
fi
|
||||
|
||||
echo "Looking for $package on device $device"
|
||||
|
||||
# Find the application data directory
|
||||
app_data_dir=`adb -s $device shell run-as $package sh -c 'pwd 2> /dev/null'`
|
||||
|
||||
if [ -z $app_data_dir ]; then
|
||||
echo "The data directory for the package $package was not found."
|
||||
echo "Is it installed?"
|
||||
fi
|
||||
|
||||
echo "Found application data directory at" "$app_data_dir"
|
||||
|
||||
# Generate an awk script to extract PIDs from Android ps output. It
|
||||
# is enough to run `ps' as the package user on newer versions of
|
||||
# Android, but that doesn't work on Android 2.3.
|
||||
cat << EOF > tmp.awk
|
||||
BEGIN {
|
||||
pid = 0;
|
||||
pid_column = 2;
|
||||
}
|
||||
|
||||
{
|
||||
# Remove any trailing carriage return from the input line.
|
||||
gsub ("\r", "", \$NF)
|
||||
|
||||
# If this is line 1, figure out which column contains the PID.
|
||||
if (NR == 1)
|
||||
{
|
||||
for (n = 1; n <= NF; ++n)
|
||||
{
|
||||
if (\$n == "PID")
|
||||
pid_column=n;
|
||||
}
|
||||
}
|
||||
else if (\$NF == "$package")
|
||||
print \$pid_column
|
||||
}
|
||||
EOF
|
||||
|
||||
# Make sure that file disappears once this script exits.
|
||||
trap "rm -f $(pwd)/tmp.awk" 0
|
||||
|
||||
# First, run ps to fetch the list of process IDs.
|
||||
package_pids=`adb -s $device shell ps`
|
||||
|
||||
# Next, extract the list of PIDs currently running.
|
||||
package_pids=`awk -f tmp.awk <<< $package_pids`
|
||||
|
||||
if [ "$attach_existing" != "yes" ]; then
|
||||
# Finally, kill each existing process.
|
||||
for pid in $package_pids; do
|
||||
echo "Killing existing process $pid..."
|
||||
adb -s $device shell run-as $package kill -9 $pid &> /dev/null
|
||||
done
|
||||
|
||||
# Now run the main activity. This must be done as the adb user and
|
||||
# not as the package user.
|
||||
echo "Starting activity $activity and attaching debugger"
|
||||
|
||||
# Exit if the activity could not be started.
|
||||
adb -s $device shell am start -D -n "$package/$activity"
|
||||
if [ ! $? ]; then
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
# Sleep for a bit. Otherwise, the process may not have started
|
||||
# yet.
|
||||
sleep 1
|
||||
|
||||
# Now look for processes matching the package again.
|
||||
package_pids=`adb -s $device shell ps`
|
||||
|
||||
# Next, remove lines matching "ps" itself.
|
||||
package_pids=`awk -f tmp.awk <<< $package_pids`
|
||||
fi
|
||||
|
||||
pid=$package_pids
|
||||
num_pids=`wc -w <<< "$package_pids"`
|
||||
|
||||
if [ $num_pids -gt 1 ]; then
|
||||
echo "More than one process was started:"
|
||||
echo ""
|
||||
adb -s $device shell run-as $package ps | awk -- "{
|
||||
if (!match (\$0, /ps/) && match (\$0, /$package/))
|
||||
print \$0
|
||||
}"
|
||||
echo ""
|
||||
printf "Which one do you want to attach to? "
|
||||
read pid
|
||||
elif [ -z $package_pids ]; then
|
||||
echo "No processes were found to attach to."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# If either --jdb was specified or debug.sh is not connecting to an
|
||||
# existing process, then store a suitable JDB invocation in
|
||||
# jdb_command. GDB will then run JDB to unblock the application from
|
||||
# the wait dialog after startup.
|
||||
|
||||
if [ "$jdb" = "yes" ] || [ "$attach_existing" != yes ]; then
|
||||
adb -s $device forward --remove-all
|
||||
adb -s $device forward "tcp:$jdb_port" "jdwp:$pid"
|
||||
|
||||
if [ ! $? ]; then
|
||||
echo "Failed to forward jdwp:$pid to $jdb_port!"
|
||||
echo "Perhaps you need to specify a different port with --port?"
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
jdb_command="jdb -connect \
|
||||
com.sun.jdi.SocketAttach:hostname=localhost,port=$jdb_port"
|
||||
|
||||
if [ $jdb = "yes" ]; then
|
||||
# Just start JDB and then exit
|
||||
$jdb_command
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$jdb_command" ]; then
|
||||
echo "Starting JDB to unblock application."
|
||||
|
||||
# Start JDB to unblock the application.
|
||||
coproc JDB { $jdb_command; }
|
||||
|
||||
# Tell JDB to first suspend all threads.
|
||||
echo "suspend" >&${JDB[1]}
|
||||
|
||||
# Tell JDB to print a magic string once the program is
|
||||
# initialized.
|
||||
echo "print \"__verify_jdb_has_started__\"" >&${JDB[1]}
|
||||
|
||||
# Now wait for JDB to give the string back.
|
||||
line=
|
||||
while :; do
|
||||
read -u ${JDB[0]} line
|
||||
if [ ! $? ]; then
|
||||
echo "Failed to read JDB output"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case "$line" in
|
||||
*__verify_jdb_has_started__*)
|
||||
# Android only polls for a Java debugger every 200ms, so
|
||||
# the debugger must be connected for at least that long.
|
||||
echo "Pausing 1 second for the program to continue."
|
||||
sleep 1
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Note that JDB does not exit until GDB is fully attached!
|
||||
fi
|
||||
|
||||
# See if gdbserver has to be uploaded
|
||||
gdbserver_cmd=
|
||||
is_root=
|
||||
if [ -z "$gdbserver" ]; then
|
||||
gdbserver_bin=/system/bin/gdbserver64
|
||||
else
|
||||
gdbserver_bin=/data/local/tmp/gdbserver
|
||||
gdbserver_cat="cat $gdbserver_bin | run-as $package sh -c \
|
||||
\"tee gdbserver > /dev/null\""
|
||||
|
||||
# Upload the specified gdbserver binary to the device.
|
||||
adb -s $device push "$gdbserver" "$gdbserver_bin"
|
||||
|
||||
if (adb -s $device shell ls /system/bin | grep -G tee); then
|
||||
# Copy it to the user directory.
|
||||
adb -s $device shell "$gdbserver_cat"
|
||||
adb -s $device shell "run-as $package chmod 777 gdbserver"
|
||||
gdbserver_cmd="./gdbserver"
|
||||
else
|
||||
# Hopefully this is an old version of Android which allows
|
||||
# execution from /data/local/tmp. Its `chmod' doesn't support
|
||||
# `+x' either.
|
||||
adb -s $device shell "chmod 777 $gdbserver_bin"
|
||||
gdbserver_cmd="$gdbserver_bin"
|
||||
|
||||
# If the user is root, then there is no need to open any kind
|
||||
# of TCP socket.
|
||||
if (adb -s $device shell id | grep -G root); then
|
||||
gdbserver=
|
||||
is_root=yes
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Now start gdbserver on the device asynchronously.
|
||||
|
||||
echo "Attaching gdbserver to $pid on $device..."
|
||||
exec 5<> /tmp/file-descriptor-stamp
|
||||
rm -f /tmp/file-descriptor-stamp
|
||||
|
||||
if [ -z "$gdbserver" ]; then
|
||||
if [ "$is_root" = "yes" ]; then
|
||||
adb -s $device shell $gdbserver_bin --multi \
|
||||
"0.0.0.0:7564" --attach $pid >&5 &
|
||||
gdb_socket="tcp:7564"
|
||||
else
|
||||
adb -s $device shell $gdbserver_bin --multi \
|
||||
"0.0.0.0:7564" --attach $pid >&5 &
|
||||
gdb_socket="tcp:7564"
|
||||
fi
|
||||
else
|
||||
# Normally the program cannot access $gdbserver_bin when it is
|
||||
# placed in /data/local/tmp.
|
||||
adb -s $device shell run-as $package $gdbserver_cmd --multi \
|
||||
"+debug.$package.socket" --attach $pid >&5 &
|
||||
gdb_socket="localfilesystem:$app_data_dir/debug.$package.socket"
|
||||
fi
|
||||
|
||||
# In order to allow adb to forward to the gdbserver socket, make the
|
||||
# app data directory a+x.
|
||||
adb -s $device shell run-as $package chmod a+x $app_data_dir
|
||||
|
||||
# Wait until gdbserver successfully runs.
|
||||
line=
|
||||
while read -u 5 line; do
|
||||
case "$line" in
|
||||
*Attached* )
|
||||
break;
|
||||
;;
|
||||
*error* | *Error* | failed )
|
||||
echo "GDB error:" $line
|
||||
exit 1
|
||||
;;
|
||||
* )
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Now that GDB is attached, tell the Java debugger to resume execution
|
||||
# and then exit.
|
||||
|
||||
if [ -n "$jdb_command" ]; then
|
||||
echo "resume" >&${JDB[1]}
|
||||
echo "exit" >&${JDB[1]}
|
||||
fi
|
||||
|
||||
# Forward the gdb server port here.
|
||||
adb -s $device forward "tcp:$gdb_port" $gdb_socket
|
||||
if [ ! $? ]; then
|
||||
echo "Failed to forward $app_data_dir/debug.$package.socket"
|
||||
echo "to $gdb_port! Perhaps you need to specify a different port"
|
||||
echo "with --port?"
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
# Finally, start gdb with any extra arguments needed.
|
||||
cd "$oldpwd"
|
||||
$gdb --eval-command "target remote localhost:$gdb_port" $gdbargs
|
BIN
java/emacs.keystore
Normal file
BIN
java/emacs.keystore
Normal file
Binary file not shown.
481
java/org/gnu/emacs/EmacsActivity.java
Normal file
481
java/org/gnu/emacs/EmacsActivity.java
Normal file
|
@ -0,0 +1,481 @@
|
|||
/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
|
||||
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
package org.gnu.emacs;
|
||||
|
||||
import java.lang.IllegalStateException;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import android.view.Menu;
|
||||
import android.view.View;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.Window;
|
||||
import android.view.WindowInsets;
|
||||
import android.view.WindowInsetsController;
|
||||
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
public class EmacsActivity extends Activity
|
||||
implements EmacsWindowAttachmentManager.WindowConsumer,
|
||||
ViewTreeObserver.OnGlobalLayoutListener
|
||||
{
|
||||
public static final String TAG = "EmacsActivity";
|
||||
|
||||
/* ID for URIs from a granted document tree. */
|
||||
public static final int ACCEPT_DOCUMENT_TREE = 1;
|
||||
|
||||
/* The currently attached EmacsWindow, or null if none. */
|
||||
private EmacsWindow window;
|
||||
|
||||
/* The frame layout associated with the activity. */
|
||||
private FrameLayout layout;
|
||||
|
||||
/* List of activities with focus. */
|
||||
public static final List<EmacsActivity> focusedActivities;
|
||||
|
||||
/* The last activity to have been focused. */
|
||||
public static EmacsActivity lastFocusedActivity;
|
||||
|
||||
/* The currently focused window. */
|
||||
public static EmacsWindow focusedWindow;
|
||||
|
||||
/* Whether or not this activity is paused. */
|
||||
private boolean isPaused;
|
||||
|
||||
/* Whether or not this activity is fullscreen. */
|
||||
private boolean isFullscreen;
|
||||
|
||||
/* The last context menu to be closed. */
|
||||
private static Menu lastClosedMenu;
|
||||
|
||||
static
|
||||
{
|
||||
focusedActivities = new ArrayList<EmacsActivity> ();
|
||||
};
|
||||
|
||||
public static void
|
||||
invalidateFocus1 (EmacsWindow window)
|
||||
{
|
||||
if (window.view.isFocused ())
|
||||
focusedWindow = window;
|
||||
|
||||
for (EmacsWindow child : window.children)
|
||||
invalidateFocus1 (child);
|
||||
}
|
||||
|
||||
public static void
|
||||
invalidateFocus ()
|
||||
{
|
||||
EmacsWindow oldFocus;
|
||||
|
||||
/* Walk through each focused activity and assign the window focus
|
||||
to the bottom-most focused window within. Record the old focus
|
||||
as well. */
|
||||
oldFocus = focusedWindow;
|
||||
focusedWindow = null;
|
||||
|
||||
for (EmacsActivity activity : focusedActivities)
|
||||
{
|
||||
if (activity.window != null)
|
||||
invalidateFocus1 (activity.window);
|
||||
}
|
||||
|
||||
/* Send focus in- and out- events to the previous and current
|
||||
focus. */
|
||||
|
||||
if (oldFocus != null)
|
||||
EmacsNative.sendFocusOut (oldFocus.handle,
|
||||
System.currentTimeMillis ());
|
||||
|
||||
if (focusedWindow != null)
|
||||
EmacsNative.sendFocusIn (focusedWindow.handle,
|
||||
System.currentTimeMillis ());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void
|
||||
detachWindow ()
|
||||
{
|
||||
syncFullscreenWith (null);
|
||||
|
||||
if (window == null)
|
||||
Log.w (TAG, "detachWindow called, but there is no window");
|
||||
else
|
||||
{
|
||||
/* Clear the window's pointer to this activity and remove the
|
||||
window's view. */
|
||||
window.setConsumer (null);
|
||||
|
||||
/* The window can't be iconified any longer. */
|
||||
window.noticeDeiconified ();
|
||||
layout.removeView (window.view);
|
||||
window = null;
|
||||
|
||||
invalidateFocus ();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void
|
||||
attachWindow (EmacsWindow child)
|
||||
{
|
||||
Log.d (TAG, "attachWindow: " + child);
|
||||
|
||||
if (window != null)
|
||||
throw new IllegalStateException ("trying to attach window when one"
|
||||
+ " already exists");
|
||||
|
||||
syncFullscreenWith (child);
|
||||
|
||||
/* Record and attach the view. */
|
||||
|
||||
window = child;
|
||||
layout.addView (window.view);
|
||||
child.setConsumer (this);
|
||||
|
||||
/* If the window isn't no-focus-on-map, focus its view. */
|
||||
if (!child.getDontFocusOnMap ())
|
||||
window.view.requestFocus ();
|
||||
|
||||
/* If the activity is iconified, send that to the window. */
|
||||
if (isPaused)
|
||||
window.noticeIconified ();
|
||||
|
||||
/* Invalidate the focus. */
|
||||
invalidateFocus ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void
|
||||
destroy ()
|
||||
{
|
||||
finish ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final EmacsWindow
|
||||
getAttachedWindow ()
|
||||
{
|
||||
return window;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void
|
||||
onCreate (Bundle savedInstanceState)
|
||||
{
|
||||
FrameLayout.LayoutParams params;
|
||||
Intent intent;
|
||||
View decorView;
|
||||
ViewTreeObserver observer;
|
||||
int matchParent;
|
||||
|
||||
/* See if Emacs should be started with any extra arguments, such
|
||||
as `--quick'. */
|
||||
intent = getIntent ();
|
||||
EmacsService.extraStartupArgument
|
||||
= intent.getStringExtra ("org.gnu.emacs.STARTUP_ARGUMENT");
|
||||
|
||||
matchParent = FrameLayout.LayoutParams.MATCH_PARENT;
|
||||
params
|
||||
= new FrameLayout.LayoutParams (matchParent,
|
||||
matchParent);
|
||||
|
||||
/* Make the frame layout. */
|
||||
layout = new FrameLayout (this);
|
||||
layout.setLayoutParams (params);
|
||||
|
||||
/* Set it as the content view. */
|
||||
setContentView (layout);
|
||||
|
||||
/* Maybe start the Emacs service if necessary. */
|
||||
EmacsService.startEmacsService (this);
|
||||
|
||||
/* Add this activity to the list of available activities. */
|
||||
EmacsWindowAttachmentManager.MANAGER.registerWindowConsumer (this);
|
||||
|
||||
/* Start observing global layout changes between Jelly Bean and Q.
|
||||
This is required to restore the fullscreen state whenever the
|
||||
on screen keyboard is displayed, as there is otherwise no way
|
||||
to determine when the on screen keyboard becomes visible. */
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN
|
||||
&& Build.VERSION.SDK_INT < Build.VERSION_CODES.R)
|
||||
{
|
||||
decorView = getWindow ().getDecorView ();
|
||||
observer = decorView.getViewTreeObserver ();
|
||||
observer.addOnGlobalLayoutListener (this);
|
||||
}
|
||||
|
||||
super.onCreate (savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void
|
||||
onGlobalLayout ()
|
||||
{
|
||||
syncFullscreenWith (window);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void
|
||||
onDestroy ()
|
||||
{
|
||||
EmacsWindowAttachmentManager manager;
|
||||
boolean isMultitask;
|
||||
|
||||
manager = EmacsWindowAttachmentManager.MANAGER;
|
||||
|
||||
/* The activity will die shortly hereafter. If there is a window
|
||||
attached, close it now. */
|
||||
Log.d (TAG, "onDestroy " + this);
|
||||
isMultitask = this instanceof EmacsMultitaskActivity;
|
||||
manager.removeWindowConsumer (this, isMultitask || isFinishing ());
|
||||
focusedActivities.remove (this);
|
||||
invalidateFocus ();
|
||||
|
||||
/* Remove this activity from the static field, lest it leak. */
|
||||
if (lastFocusedActivity == this)
|
||||
lastFocusedActivity = null;
|
||||
|
||||
super.onDestroy ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void
|
||||
onWindowFocusChanged (boolean isFocused)
|
||||
{
|
||||
Log.d (TAG, ("onWindowFocusChanged: "
|
||||
+ (isFocused ? "YES" : "NO")));
|
||||
|
||||
if (isFocused && !focusedActivities.contains (this))
|
||||
{
|
||||
focusedActivities.add (this);
|
||||
lastFocusedActivity = this;
|
||||
|
||||
/* Update the window insets as the focus change may have
|
||||
changed the window insets as well, and the system does not
|
||||
automatically restore visibility flags. */
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN
|
||||
&& Build.VERSION.SDK_INT < Build.VERSION_CODES.R
|
||||
&& isFullscreen)
|
||||
syncFullscreenWith (window);
|
||||
}
|
||||
else
|
||||
focusedActivities.remove (this);
|
||||
|
||||
invalidateFocus ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void
|
||||
onPause ()
|
||||
{
|
||||
isPaused = true;
|
||||
|
||||
EmacsWindowAttachmentManager.MANAGER.noticeIconified (this);
|
||||
super.onPause ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void
|
||||
onResume ()
|
||||
{
|
||||
isPaused = false;
|
||||
|
||||
EmacsWindowAttachmentManager.MANAGER.noticeDeiconified (this);
|
||||
super.onResume ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void
|
||||
onContextMenuClosed (Menu menu)
|
||||
{
|
||||
int serial;
|
||||
|
||||
Log.d (TAG, "onContextMenuClosed: " + menu);
|
||||
|
||||
/* See the comment inside onMenuItemClick. */
|
||||
|
||||
if (((EmacsContextMenu.wasSubmenuSelected == -2)
|
||||
|| (EmacsContextMenu.wasSubmenuSelected >= 0
|
||||
&& ((System.currentTimeMillis ()
|
||||
- EmacsContextMenu.wasSubmenuSelected)
|
||||
<= 300)))
|
||||
|| menu == lastClosedMenu)
|
||||
{
|
||||
EmacsContextMenu.wasSubmenuSelected = -1;
|
||||
lastClosedMenu = menu;
|
||||
return;
|
||||
}
|
||||
|
||||
/* lastClosedMenu is set because Android apparently calls this
|
||||
function twice. */
|
||||
|
||||
lastClosedMenu = null;
|
||||
|
||||
/* Send a context menu event given that no menu item has already
|
||||
been selected. */
|
||||
if (!EmacsContextMenu.itemAlreadySelected)
|
||||
{
|
||||
serial = EmacsContextMenu.lastMenuEventSerial;
|
||||
EmacsNative.sendContextMenu ((short) 0, 0,
|
||||
serial);
|
||||
}
|
||||
|
||||
super.onContextMenuClosed (menu);
|
||||
}
|
||||
|
||||
@SuppressWarnings ("deprecation")
|
||||
public final void
|
||||
syncFullscreenWith (EmacsWindow emacsWindow)
|
||||
{
|
||||
WindowInsetsController controller;
|
||||
Window window;
|
||||
int behavior, flags;
|
||||
View view;
|
||||
|
||||
if (emacsWindow != null)
|
||||
isFullscreen = emacsWindow.fullscreen;
|
||||
else
|
||||
isFullscreen = false;
|
||||
|
||||
/* On Android 11 or later, use the window insets controller to
|
||||
control whether or not the view is fullscreen. */
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
|
||||
{
|
||||
window = getWindow ();
|
||||
|
||||
/* If there is no attached window, return immediately. */
|
||||
if (window == null)
|
||||
return;
|
||||
|
||||
behavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
|
||||
controller = window.getInsetsController ();
|
||||
controller.setSystemBarsBehavior (behavior);
|
||||
|
||||
if (isFullscreen)
|
||||
controller.hide (WindowInsets.Type.statusBars ()
|
||||
| WindowInsets.Type.navigationBars ());
|
||||
else
|
||||
controller.show (WindowInsets.Type.statusBars ()
|
||||
| WindowInsets.Type.navigationBars ());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
|
||||
{
|
||||
/* On Android 4.1 or later, use `setSystemUiVisibility'. */
|
||||
|
||||
window = getWindow ();
|
||||
|
||||
if (window == null)
|
||||
return;
|
||||
|
||||
view = window.getDecorView ();
|
||||
|
||||
if (isFullscreen)
|
||||
{
|
||||
flags = 0;
|
||||
flags |= View.SYSTEM_UI_FLAG_FULLSCREEN;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
|
||||
{
|
||||
/* These flags means that Emacs will be full screen as
|
||||
long as the state flag is set. */
|
||||
flags |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
|
||||
flags |= View.SYSTEM_UI_FLAG_IMMERSIVE;
|
||||
flags |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
|
||||
}
|
||||
|
||||
/* Apply the given flags. */
|
||||
view.setSystemUiVisibility (flags);
|
||||
}
|
||||
else
|
||||
view.setSystemUiVisibility (View.SYSTEM_UI_FLAG_VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void
|
||||
onAttachedToWindow ()
|
||||
{
|
||||
super.onAttachedToWindow ();
|
||||
|
||||
/* Update the window insets. */
|
||||
syncFullscreenWith (window);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public final void
|
||||
onActivityResult (int requestCode, int resultCode, Intent data)
|
||||
{
|
||||
ContentResolver resolver;
|
||||
Uri uri;
|
||||
int flags;
|
||||
|
||||
switch (requestCode)
|
||||
{
|
||||
case ACCEPT_DOCUMENT_TREE:
|
||||
|
||||
/* A document granted through
|
||||
EmacsService.requestDirectoryAccess. */
|
||||
|
||||
if (resultCode == RESULT_OK)
|
||||
{
|
||||
resolver = getContentResolver ();
|
||||
uri = data.getData ();
|
||||
flags = (Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||
|
||||
try
|
||||
{
|
||||
if (uri != null)
|
||||
resolver.takePersistableUriPermission (uri, flags);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
/* Permission to access URI might've been revoked in
|
||||
between selecting the file and this callback being
|
||||
invoked. Don't crash in such cases. */
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
92
java/org/gnu/emacs/EmacsApplication.java
Normal file
92
java/org/gnu/emacs/EmacsApplication.java
Normal file
|
@ -0,0 +1,92 @@
|
|||
/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
|
||||
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
package org.gnu.emacs;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import android.app.Application;
|
||||
import android.util.Log;
|
||||
|
||||
public final class EmacsApplication extends Application
|
||||
{
|
||||
private static final String TAG = "EmacsApplication";
|
||||
|
||||
/* The name of the dump file to use. */
|
||||
public static String dumpFileName;
|
||||
|
||||
public static void
|
||||
findDumpFile (Context context)
|
||||
{
|
||||
File filesDirectory;
|
||||
File[] allFiles;
|
||||
String wantedDumpFile;
|
||||
int i;
|
||||
|
||||
wantedDumpFile = ("emacs-" + EmacsNative.getFingerprint ()
|
||||
+ ".pdmp");
|
||||
|
||||
/* Obtain a list of all files ending with ``.pdmp''. Then, look
|
||||
for a file named ``emacs-<fingerprint>.pdmp'' and delete the
|
||||
rest. */
|
||||
filesDirectory = context.getFilesDir ();
|
||||
|
||||
allFiles = filesDirectory.listFiles (new FileFilter () {
|
||||
@Override
|
||||
public boolean
|
||||
accept (File file)
|
||||
{
|
||||
return (!file.isDirectory ()
|
||||
&& file.getName ().endsWith (".pdmp"));
|
||||
}
|
||||
});
|
||||
|
||||
if (allFiles == null)
|
||||
return;
|
||||
|
||||
/* Now try to find the right dump file. */
|
||||
for (i = 0; i < allFiles.length; ++i)
|
||||
{
|
||||
if (allFiles[i].getName ().equals (wantedDumpFile))
|
||||
dumpFileName = allFiles[i].getAbsolutePath ();
|
||||
else
|
||||
/* Delete this outdated dump file. */
|
||||
allFiles[i].delete ();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void
|
||||
onCreate ()
|
||||
{
|
||||
/* Block signals which don't interest the current thread and its
|
||||
descendants created by the system. The original signal mask
|
||||
will be restored for the Emacs thread in `initEmacs'. */
|
||||
EmacsNative.setupSystemThread ();
|
||||
|
||||
/* Locate a suitable dump file. */
|
||||
findDumpFile (this);
|
||||
|
||||
/* Start the rest of the application. */
|
||||
super.onCreate ();
|
||||
}
|
||||
};
|
47
java/org/gnu/emacs/EmacsClipboard.java
Normal file
47
java/org/gnu/emacs/EmacsClipboard.java
Normal file
|
@ -0,0 +1,47 @@
|
|||
/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
|
||||
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
package org.gnu.emacs;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
/* This class provides helper code for accessing the clipboard,
|
||||
abstracting between the different interfaces on API 8 and 11. */
|
||||
|
||||
public abstract class EmacsClipboard
|
||||
{
|
||||
public abstract void setClipboard (byte[] bytes);
|
||||
public abstract int ownsClipboard ();
|
||||
public abstract boolean clipboardExists ();
|
||||
public abstract byte[] getClipboard ();
|
||||
|
||||
public abstract byte[][] getClipboardTargets ();
|
||||
public abstract long[] getClipboardData (byte[] target);
|
||||
|
||||
/* Create the correct kind of clipboard for this system. */
|
||||
|
||||
public static EmacsClipboard
|
||||
makeClipboard ()
|
||||
{
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
|
||||
return new EmacsSdk11Clipboard ();
|
||||
else
|
||||
return new EmacsSdk8Clipboard ();
|
||||
}
|
||||
};
|
393
java/org/gnu/emacs/EmacsContextMenu.java
Normal file
393
java/org/gnu/emacs/EmacsContextMenu.java
Normal file
|
@ -0,0 +1,393 @@
|
|||
/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
|
||||
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
package org.gnu.emacs;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import android.view.ContextMenu;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.SubMenu;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
/* Context menu implementation. This object is built from JNI and
|
||||
describes a menu hiearchy. Then, `inflate' can turn it into an
|
||||
Android menu, which can be turned into a popup (or other kind of)
|
||||
menu. */
|
||||
|
||||
public final class EmacsContextMenu
|
||||
{
|
||||
private static final String TAG = "EmacsContextMenu";
|
||||
|
||||
/* Whether or not an item was selected. */
|
||||
public static boolean itemAlreadySelected;
|
||||
|
||||
/* Whether or not a submenu was selected.
|
||||
Value is -1 if no; value is -2 if yes, and a context menu
|
||||
close event will definitely be sent. Any other value is
|
||||
the timestamp when the submenu was selected. */
|
||||
public static long wasSubmenuSelected;
|
||||
|
||||
/* The serial ID of the last context menu to be displayed. */
|
||||
public static int lastMenuEventSerial;
|
||||
|
||||
/* The last group ID used for a menu item. */
|
||||
public int lastGroupId;
|
||||
|
||||
private static final class Item implements MenuItem.OnMenuItemClickListener
|
||||
{
|
||||
public int itemID;
|
||||
public String itemName, tooltip;
|
||||
public EmacsContextMenu subMenu;
|
||||
public boolean isEnabled, isCheckable, isChecked;
|
||||
public EmacsView inflatedView;
|
||||
public boolean isRadio;
|
||||
|
||||
@Override
|
||||
public boolean
|
||||
onMenuItemClick (MenuItem item)
|
||||
{
|
||||
Log.d (TAG, "onMenuItemClick: " + itemName + " (" + itemID + ")");
|
||||
|
||||
if (subMenu != null)
|
||||
{
|
||||
/* Android 6.0 and earlier don't support nested submenus
|
||||
properly, so display the submenu popup by hand. */
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N)
|
||||
{
|
||||
Log.d (TAG, "onMenuItemClick: displaying submenu " + subMenu);
|
||||
|
||||
/* Still set wasSubmenuSelected -- if not set, the
|
||||
dismissal of this context menu will result in a
|
||||
context menu event being sent. */
|
||||
wasSubmenuSelected = -2;
|
||||
|
||||
/* Running a popup menu from inside a click handler
|
||||
doesn't work, so make sure it is displayed
|
||||
outside. */
|
||||
|
||||
inflatedView.post (new Runnable () {
|
||||
@Override
|
||||
public void
|
||||
run ()
|
||||
{
|
||||
inflatedView.popupMenu (subMenu, 0, 0, true);
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* After opening a submenu within a submenu, Android will
|
||||
send onContextMenuClosed for a ContextMenuBuilder. This
|
||||
will normally confuse Emacs into thinking that the
|
||||
context menu has been dismissed. Wrong!
|
||||
|
||||
Setting this flag makes EmacsActivity to only handle
|
||||
SubMenuBuilder being closed, which always means the menu
|
||||
has actually been dismissed.
|
||||
|
||||
However, these extraneous events aren't sent on devices
|
||||
where submenus display without dismissing their parents.
|
||||
Thus, only ignore the close event if it happens within
|
||||
300 milliseconds of the submenu being selected. */
|
||||
wasSubmenuSelected = System.currentTimeMillis ();
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Send a context menu event. */
|
||||
EmacsNative.sendContextMenu ((short) 0, itemID,
|
||||
lastMenuEventSerial);
|
||||
|
||||
/* Say that an item has already been selected. */
|
||||
itemAlreadySelected = true;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/* List of menu items contained in this menu. */
|
||||
public List<Item> menuItems;
|
||||
|
||||
/* The parent context menu, or NULL if none. */
|
||||
private EmacsContextMenu parent;
|
||||
|
||||
/* The title of this context menu, or NULL if none. */
|
||||
private String title;
|
||||
|
||||
|
||||
|
||||
/* Create a context menu with no items inside and the title TITLE,
|
||||
which may be NULL. */
|
||||
|
||||
public static EmacsContextMenu
|
||||
createContextMenu (String title)
|
||||
{
|
||||
EmacsContextMenu menu;
|
||||
|
||||
menu = new EmacsContextMenu ();
|
||||
menu.title = title;
|
||||
menu.menuItems = new ArrayList<Item> ();
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
/* Add a normal menu item to the context menu with the id ITEMID and
|
||||
the name ITEMNAME. Enable it if ISENABLED, else keep it
|
||||
disabled.
|
||||
|
||||
If this is not a submenu and ISCHECKABLE is set, make the item
|
||||
checkable. Likewise, if ISCHECKED is set, make the item
|
||||
checked.
|
||||
|
||||
If TOOLTIP is non-NULL, set the menu item tooltip to TOOLTIP.
|
||||
|
||||
If ISRADIO, then display the check mark as a radio button. */
|
||||
|
||||
public void
|
||||
addItem (int itemID, String itemName, boolean isEnabled,
|
||||
boolean isCheckable, boolean isChecked,
|
||||
String tooltip, boolean isRadio)
|
||||
{
|
||||
Item item;
|
||||
|
||||
item = new Item ();
|
||||
item.itemID = itemID;
|
||||
item.itemName = itemName;
|
||||
item.isEnabled = isEnabled;
|
||||
item.isCheckable = isCheckable;
|
||||
item.isChecked = isChecked;
|
||||
item.tooltip = tooltip;
|
||||
item.isRadio = isRadio;
|
||||
|
||||
menuItems.add (item);
|
||||
}
|
||||
|
||||
/* Create a disabled menu item with the name ITEMNAME. */
|
||||
|
||||
public void
|
||||
addPane (String itemName)
|
||||
{
|
||||
Item item;
|
||||
|
||||
item = new Item ();
|
||||
item.itemName = itemName;
|
||||
|
||||
menuItems.add (item);
|
||||
}
|
||||
|
||||
/* Add a submenu to the context menu with the specified title and
|
||||
item name. */
|
||||
|
||||
public EmacsContextMenu
|
||||
addSubmenu (String itemName, String tooltip)
|
||||
{
|
||||
EmacsContextMenu submenu;
|
||||
Item item;
|
||||
|
||||
item = new Item ();
|
||||
item.itemID = 0;
|
||||
item.itemName = itemName;
|
||||
item.tooltip = tooltip;
|
||||
item.subMenu = createContextMenu (itemName);
|
||||
item.subMenu.parent = this;
|
||||
|
||||
menuItems.add (item);
|
||||
return item.subMenu;
|
||||
}
|
||||
|
||||
/* Add the contents of this menu to MENU. Assume MENU will be
|
||||
displayed in INFLATEDVIEW. */
|
||||
|
||||
private void
|
||||
inflateMenuItems (Menu menu, EmacsView inflatedView)
|
||||
{
|
||||
Intent intent;
|
||||
MenuItem menuItem;
|
||||
SubMenu submenu;
|
||||
|
||||
for (Item item : menuItems)
|
||||
{
|
||||
if (item.subMenu != null)
|
||||
{
|
||||
/* This is a submenu. On versions of Android which
|
||||
support doing so, create the submenu and add the
|
||||
contents of the menu to it.
|
||||
|
||||
Note that Android 4.0 and later technically supports
|
||||
having multiple layers of nested submenus, but if they
|
||||
are used, onContextMenuClosed becomes unreliable. */
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
|
||||
{
|
||||
submenu = menu.addSubMenu (item.itemName);
|
||||
item.subMenu.inflateMenuItems (submenu, inflatedView);
|
||||
|
||||
/* This is still needed to set wasSubmenuSelected. */
|
||||
menuItem = submenu.getItem ();
|
||||
}
|
||||
else
|
||||
menuItem = menu.add (item.itemName);
|
||||
|
||||
item.inflatedView = inflatedView;
|
||||
menuItem.setOnMenuItemClickListener (item);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (item.isRadio)
|
||||
menuItem = menu.add (++lastGroupId, Menu.NONE, Menu.NONE,
|
||||
item.itemName);
|
||||
else
|
||||
menuItem = menu.add (item.itemName);
|
||||
menuItem.setOnMenuItemClickListener (item);
|
||||
|
||||
/* If the item ID is zero, then disable the item. */
|
||||
if (item.itemID == 0 || !item.isEnabled)
|
||||
menuItem.setEnabled (false);
|
||||
|
||||
/* Now make the menu item display a checkmark as
|
||||
appropriate. */
|
||||
|
||||
if (item.isCheckable)
|
||||
menuItem.setCheckable (true);
|
||||
|
||||
if (item.isChecked)
|
||||
menuItem.setChecked (true);
|
||||
|
||||
/* Define an exclusively checkable group if the item is a
|
||||
radio button. */
|
||||
|
||||
if (item.isRadio)
|
||||
menu.setGroupCheckable (lastGroupId, true, true);
|
||||
|
||||
/* If the tooltip text is set and the system is new enough
|
||||
to support menu item tooltips, set it on the item. */
|
||||
|
||||
if (item.tooltip != null
|
||||
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
||||
menuItem.setTooltipText (item.tooltip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Enter the items in this context menu to MENU.
|
||||
Assume that MENU will be displayed in VIEW; this may lead to
|
||||
popupMenu being called on VIEW if a submenu is selected.
|
||||
|
||||
If MENU is a ContextMenu, set its header title to the one
|
||||
contained in this object. */
|
||||
|
||||
public void
|
||||
expandTo (Menu menu, EmacsView view)
|
||||
{
|
||||
inflateMenuItems (menu, view);
|
||||
|
||||
/* See if menu is a ContextMenu and a title is set. */
|
||||
if (title == null || !(menu instanceof ContextMenu))
|
||||
return;
|
||||
|
||||
/* Set its title to this.title. */
|
||||
((ContextMenu) menu).setHeaderTitle (title);
|
||||
}
|
||||
|
||||
/* Return the parent or NULL. */
|
||||
|
||||
public EmacsContextMenu
|
||||
parent ()
|
||||
{
|
||||
return this.parent;
|
||||
}
|
||||
|
||||
/* Like display, but does the actual work and runs in the main
|
||||
thread. */
|
||||
|
||||
private boolean
|
||||
display1 (EmacsWindow window, int xPosition, int yPosition)
|
||||
{
|
||||
/* Set this flag to false. It is used to decide whether or not to
|
||||
send 0 in response to the context menu being closed. */
|
||||
itemAlreadySelected = false;
|
||||
|
||||
/* No submenu has been selected yet. */
|
||||
wasSubmenuSelected = -1;
|
||||
|
||||
return window.view.popupMenu (this, xPosition, yPosition,
|
||||
false);
|
||||
}
|
||||
|
||||
/* Display this context menu on WINDOW, at xPosition and yPosition.
|
||||
SERIAL is a number that will be returned in any menu event
|
||||
generated to identify this context menu. */
|
||||
|
||||
public boolean
|
||||
display (final EmacsWindow window, final int xPosition,
|
||||
final int yPosition, final int serial)
|
||||
{
|
||||
Runnable runnable;
|
||||
final EmacsHolder<Boolean> rc;
|
||||
|
||||
rc = new EmacsHolder<Boolean> ();
|
||||
rc.thing = false;
|
||||
|
||||
runnable = new Runnable () {
|
||||
@Override
|
||||
public void
|
||||
run ()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
lastMenuEventSerial = serial;
|
||||
rc.thing = display1 (window, xPosition, yPosition);
|
||||
notify ();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
EmacsService.syncRunnable (runnable);
|
||||
return rc.thing;
|
||||
}
|
||||
|
||||
/* Dismiss this context menu. WINDOW is the window where the
|
||||
context menu is being displayed. */
|
||||
|
||||
public void
|
||||
dismiss (final EmacsWindow window)
|
||||
{
|
||||
Runnable runnable;
|
||||
|
||||
EmacsService.SERVICE.runOnUiThread (new Runnable () {
|
||||
@Override
|
||||
public void
|
||||
run ()
|
||||
{
|
||||
window.view.cancelPopupMenu ();
|
||||
itemAlreadySelected = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
47
java/org/gnu/emacs/EmacsCursor.java
Normal file
47
java/org/gnu/emacs/EmacsCursor.java
Normal file
|
@ -0,0 +1,47 @@
|
|||
/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
|
||||
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
package org.gnu.emacs;
|
||||
|
||||
import android.view.PointerIcon;
|
||||
import android.os.Build;
|
||||
|
||||
/* Cursor wrapper. Note that pointer icons are not supported prior to
|
||||
Android 24. */
|
||||
|
||||
public final class EmacsCursor extends EmacsHandleObject
|
||||
{
|
||||
/* The pointer icon associated with this cursor. */
|
||||
public final PointerIcon icon;
|
||||
|
||||
public
|
||||
EmacsCursor (short handle, int glyph)
|
||||
{
|
||||
super (handle);
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N)
|
||||
{
|
||||
icon = null;
|
||||
return;
|
||||
}
|
||||
|
||||
icon = PointerIcon.getSystemIcon (EmacsService.SERVICE,
|
||||
glyph);
|
||||
}
|
||||
};
|
427
java/org/gnu/emacs/EmacsDialog.java
Normal file
427
java/org/gnu/emacs/EmacsDialog.java
Normal file
|
@ -0,0 +1,427 @@
|
|||
/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
|
||||
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
package org.gnu.emacs;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
|
||||
import android.content.res.Resources.NotFoundException;
|
||||
import android.content.res.Resources.Theme;
|
||||
import android.content.res.TypedArray;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import android.provider.Settings;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
|
||||
/* Toolkit dialog implementation. This object is built from JNI and
|
||||
describes a single alert dialog. Then, `inflate' turns it into
|
||||
AlertDialog. */
|
||||
|
||||
public final class EmacsDialog implements DialogInterface.OnDismissListener
|
||||
{
|
||||
private static final String TAG = "EmacsDialog";
|
||||
|
||||
/* List of buttons in this dialog. */
|
||||
private List<EmacsButton> buttons;
|
||||
|
||||
/* Dialog title. */
|
||||
private String title;
|
||||
|
||||
/* Dialog text. */
|
||||
private String text;
|
||||
|
||||
/* Whether or not a selection has already been made. */
|
||||
private boolean wasButtonClicked;
|
||||
|
||||
/* Dialog to dismiss after click. */
|
||||
private AlertDialog dismissDialog;
|
||||
|
||||
/* The menu serial associated with this dialog box. */
|
||||
private int menuEventSerial;
|
||||
|
||||
private final class EmacsButton implements View.OnClickListener,
|
||||
DialogInterface.OnClickListener
|
||||
{
|
||||
/* Name of this button. */
|
||||
public String name;
|
||||
|
||||
/* ID of this button. */
|
||||
public int id;
|
||||
|
||||
/* Whether or not the button is enabled. */
|
||||
public boolean enabled;
|
||||
|
||||
@Override
|
||||
public void
|
||||
onClick (View view)
|
||||
{
|
||||
Log.d (TAG, "onClicked " + this);
|
||||
|
||||
wasButtonClicked = true;
|
||||
EmacsNative.sendContextMenu ((short) 0, id, menuEventSerial);
|
||||
dismissDialog.dismiss ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void
|
||||
onClick (DialogInterface dialog, int which)
|
||||
{
|
||||
Log.d (TAG, "onClicked " + this);
|
||||
|
||||
wasButtonClicked = true;
|
||||
EmacsNative.sendContextMenu ((short) 0, id, menuEventSerial);
|
||||
}
|
||||
};
|
||||
|
||||
/* Create a popup dialog with the title TITLE and the text TEXT.
|
||||
TITLE may be NULL. MENUEVENTSERIAL is a number which will
|
||||
identify this popup dialog inside events it sends. */
|
||||
|
||||
public static EmacsDialog
|
||||
createDialog (String title, String text, int menuEventSerial)
|
||||
{
|
||||
EmacsDialog dialog;
|
||||
|
||||
dialog = new EmacsDialog ();
|
||||
dialog.buttons = new ArrayList<EmacsButton> ();
|
||||
dialog.title = title;
|
||||
dialog.text = text;
|
||||
dialog.menuEventSerial = menuEventSerial;
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
/* Add a button named NAME, with the identifier ID. If DISABLE,
|
||||
disable the button. */
|
||||
|
||||
public void
|
||||
addButton (String name, int id, boolean disable)
|
||||
{
|
||||
EmacsButton button;
|
||||
|
||||
button = new EmacsButton ();
|
||||
button.name = name;
|
||||
button.id = id;
|
||||
button.enabled = !disable;
|
||||
buttons.add (button);
|
||||
}
|
||||
|
||||
/* Turn this dialog into an AlertDialog for the specified
|
||||
CONTEXT.
|
||||
|
||||
Upon a button being selected, the dialog will send an
|
||||
ANDROID_CONTEXT_MENU event with the id of that button.
|
||||
|
||||
Upon the dialog being dismissed, an ANDROID_CONTEXT_MENU event
|
||||
will be sent with an id of 0. */
|
||||
|
||||
public AlertDialog
|
||||
toAlertDialog (Context context)
|
||||
{
|
||||
AlertDialog dialog;
|
||||
int size, styleId, flag;
|
||||
int[] attrs;
|
||||
EmacsButton button;
|
||||
EmacsDialogButtonLayout layout;
|
||||
Button buttonView;
|
||||
ViewGroup.LayoutParams layoutParams;
|
||||
Theme theme;
|
||||
TypedArray attributes;
|
||||
Window window;
|
||||
|
||||
size = buttons.size ();
|
||||
styleId = -1;
|
||||
|
||||
if (size <= 3)
|
||||
{
|
||||
dialog = new AlertDialog.Builder (context).create ();
|
||||
dialog.setMessage (text);
|
||||
dialog.setCancelable (true);
|
||||
dialog.setOnDismissListener (this);
|
||||
|
||||
if (title != null)
|
||||
dialog.setTitle (title);
|
||||
|
||||
/* There are less than 4 buttons. Add the buttons the way
|
||||
Android intends them to be added. */
|
||||
|
||||
if (size >= 1)
|
||||
{
|
||||
button = buttons.get (0);
|
||||
dialog.setButton (DialogInterface.BUTTON_POSITIVE,
|
||||
button.name, button);
|
||||
}
|
||||
|
||||
if (size >= 2)
|
||||
{
|
||||
button = buttons.get (1);
|
||||
dialog.setButton (DialogInterface.BUTTON_NEGATIVE,
|
||||
button.name, button);
|
||||
}
|
||||
|
||||
if (size >= 3)
|
||||
{
|
||||
button = buttons.get (2);
|
||||
dialog.setButton (DialogInterface.BUTTON_NEUTRAL,
|
||||
button.name, button);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* There are more than 3 buttons. Add them all to a special
|
||||
container widget that handles wrapping. First, create the
|
||||
layout. */
|
||||
|
||||
layout = new EmacsDialogButtonLayout (context);
|
||||
layoutParams
|
||||
= new FrameLayout.LayoutParams (ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
layout.setLayoutParams (layoutParams);
|
||||
|
||||
/* Add that layout to the dialog's custom view.
|
||||
|
||||
android.R.id.custom is documented to work. But looking it
|
||||
up returns NULL, so setView must be used instead. */
|
||||
|
||||
dialog = new AlertDialog.Builder (context).setView (layout).create ();
|
||||
dialog.setMessage (text);
|
||||
dialog.setCancelable (true);
|
||||
dialog.setOnDismissListener (this);
|
||||
|
||||
if (title != null)
|
||||
dialog.setTitle (title);
|
||||
|
||||
/* Now that the dialog has been created, set the style of each
|
||||
custom button to match the usual dialog buttons found on
|
||||
Android 5 and later. */
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
|
||||
{
|
||||
/* Obtain the Theme associated with the dialog. */
|
||||
theme = dialog.getContext ().getTheme ();
|
||||
|
||||
/* Resolve the dialog button style. */
|
||||
attrs
|
||||
= new int [] { android.R.attr.buttonBarNeutralButtonStyle, };
|
||||
|
||||
try
|
||||
{
|
||||
attributes = theme.obtainStyledAttributes (attrs);
|
||||
|
||||
/* Look for the style ID. Default to -1 if it could
|
||||
not be found. */
|
||||
styleId = attributes.getResourceId (0, -1);
|
||||
|
||||
/* Now clean up the TypedAttributes object. */
|
||||
attributes.recycle ();
|
||||
}
|
||||
catch (NotFoundException e)
|
||||
{
|
||||
/* Nothing to do here. */
|
||||
}
|
||||
}
|
||||
|
||||
/* Create each button and add it to the layout. Set the style
|
||||
if necessary. */
|
||||
|
||||
for (EmacsButton emacsButton : buttons)
|
||||
{
|
||||
if (styleId == -1)
|
||||
/* No specific style... */
|
||||
buttonView = new Button (context);
|
||||
else
|
||||
/* Use the given styleId. */
|
||||
buttonView = new Button (context, null, 0, styleId);
|
||||
|
||||
/* Set the text and on click handler. */
|
||||
buttonView.setText (emacsButton.name);
|
||||
buttonView.setOnClickListener (emacsButton);
|
||||
buttonView.setEnabled (emacsButton.enabled);
|
||||
layout.addView (buttonView);
|
||||
}
|
||||
}
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
/* Internal helper for display run on the main thread. */
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private boolean
|
||||
display1 ()
|
||||
{
|
||||
Context context;
|
||||
int size, type;
|
||||
Button buttonView;
|
||||
EmacsButton button;
|
||||
AlertDialog dialog;
|
||||
Window window;
|
||||
|
||||
if (EmacsActivity.focusedActivities.isEmpty ())
|
||||
{
|
||||
/* If focusedActivities is empty then this dialog may have
|
||||
been displayed immediately after another popup dialog was
|
||||
dismissed. Or Emacs might legitimately be in the
|
||||
background, possibly displaying this popup in response to
|
||||
an Emacsclient request. Try the service context if it will
|
||||
work, then any focused EmacsOpenActivity, and finally the
|
||||
last EmacsActivity to be focused. */
|
||||
|
||||
Log.d (TAG, "display1: no focused activities...");
|
||||
Log.d (TAG, ("display1: EmacsOpenActivity.currentActivity: "
|
||||
+ EmacsOpenActivity.currentActivity));
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M
|
||||
|| Settings.canDrawOverlays (EmacsService.SERVICE))
|
||||
context = EmacsService.SERVICE;
|
||||
else if (EmacsOpenActivity.currentActivity != null)
|
||||
context = EmacsOpenActivity.currentActivity;
|
||||
else
|
||||
context = EmacsActivity.lastFocusedActivity;
|
||||
|
||||
if (context == null)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
/* Display using the activity context when Emacs is in the
|
||||
foreground, as this allows the dialog to be dismissed more
|
||||
consistently. */
|
||||
context = EmacsActivity.focusedActivities.get (0);
|
||||
|
||||
Log.d (TAG, "display1: using context " + context);
|
||||
|
||||
dialog = dismissDialog = toAlertDialog (context);
|
||||
|
||||
try
|
||||
{
|
||||
if (context == EmacsService.SERVICE)
|
||||
{
|
||||
/* Apply the system alert window type to make sure this
|
||||
dialog can be displayed. */
|
||||
|
||||
window = dialog.getWindow ();
|
||||
type = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
|
||||
? WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
|
||||
: WindowManager.LayoutParams.TYPE_PHONE);
|
||||
window.setType (type);
|
||||
}
|
||||
|
||||
dismissDialog.show ();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
/* This can happen when the system decides Emacs is not in the
|
||||
foreground any longer. */
|
||||
return false;
|
||||
}
|
||||
|
||||
/* If there are less than four buttons, then they must be
|
||||
individually enabled or disabled after the dialog is
|
||||
displayed. */
|
||||
size = buttons.size ();
|
||||
|
||||
if (size <= 3)
|
||||
{
|
||||
if (size >= 1)
|
||||
{
|
||||
button = buttons.get (0);
|
||||
buttonView
|
||||
= dialog.getButton (DialogInterface.BUTTON_POSITIVE);
|
||||
buttonView.setEnabled (button.enabled);
|
||||
}
|
||||
|
||||
if (size >= 2)
|
||||
{
|
||||
button = buttons.get (1);
|
||||
buttonView
|
||||
= dialog.getButton (DialogInterface.BUTTON_NEGATIVE);
|
||||
buttonView.setEnabled (button.enabled);
|
||||
}
|
||||
|
||||
if (size >= 3)
|
||||
{
|
||||
button = buttons.get (2);
|
||||
buttonView
|
||||
= dialog.getButton (DialogInterface.BUTTON_NEUTRAL);
|
||||
buttonView.setEnabled (button.enabled);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Display this dialog for a suitable activity.
|
||||
Value is false if the dialog could not be displayed,
|
||||
and true otherwise. */
|
||||
|
||||
public boolean
|
||||
display ()
|
||||
{
|
||||
Runnable runnable;
|
||||
final EmacsHolder<Boolean> rc;
|
||||
|
||||
rc = new EmacsHolder<Boolean> ();
|
||||
runnable = new Runnable () {
|
||||
@Override
|
||||
public void
|
||||
run ()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
rc.thing = display1 ();
|
||||
notify ();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
EmacsService.syncRunnable (runnable);
|
||||
return rc.thing;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void
|
||||
onDismiss (DialogInterface dialog)
|
||||
{
|
||||
Log.d (TAG, "onDismiss: " + this);
|
||||
|
||||
if (wasButtonClicked)
|
||||
return;
|
||||
|
||||
EmacsNative.sendContextMenu ((short) 0, 0, menuEventSerial);
|
||||
}
|
||||
};
|
152
java/org/gnu/emacs/EmacsDialogButtonLayout.java
Normal file
152
java/org/gnu/emacs/EmacsDialogButtonLayout.java
Normal file
|
@ -0,0 +1,152 @@
|
|||
/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
|
||||
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
package org.gnu.emacs;
|
||||
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.View.MeasureSpec;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
|
||||
|
||||
/* This ``view group'' implements a container widget for multiple
|
||||
buttons of the type found in pop-up dialogs. It is used when
|
||||
displaying a dialog box that contains more than three buttons, as
|
||||
the default dialog box widget is not capable of holding more than
|
||||
that many. */
|
||||
|
||||
|
||||
|
||||
public final class EmacsDialogButtonLayout extends ViewGroup
|
||||
{
|
||||
public
|
||||
EmacsDialogButtonLayout (Context context)
|
||||
{
|
||||
super (context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void
|
||||
onMeasure (int widthMeasureSpec, int heightMeasureSpec)
|
||||
{
|
||||
int width, count, i, x, y, height, spec, tempSpec;
|
||||
View view;
|
||||
|
||||
/* Obtain the width of this widget and create the measure
|
||||
specification used to measure children. */
|
||||
|
||||
width = MeasureSpec.getSize (widthMeasureSpec);
|
||||
spec = MeasureSpec.makeMeasureSpec (0, MeasureSpec.UNSPECIFIED);
|
||||
tempSpec
|
||||
= MeasureSpec.makeMeasureSpec (width, MeasureSpec.AT_MOST);
|
||||
x = y = height = 0;
|
||||
|
||||
/* Run through each widget. */
|
||||
|
||||
count = getChildCount ();
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
{
|
||||
view = getChildAt (i);
|
||||
|
||||
/* Measure this view. */
|
||||
view.measure (spec, spec);
|
||||
|
||||
if (width - x < view.getMeasuredWidth ())
|
||||
{
|
||||
/* Move onto the next line, unless this line is empty. */
|
||||
|
||||
if (x != 0)
|
||||
{
|
||||
y += height;
|
||||
height = x = 0;
|
||||
}
|
||||
|
||||
if (view.getMeasuredWidth () > width)
|
||||
/* Measure the view again, this time forcing it to be at
|
||||
most width wide, if it is not already. */
|
||||
view.measure (tempSpec, spec);
|
||||
}
|
||||
|
||||
height = Math.max (height, view.getMeasuredHeight ());
|
||||
x += view.getMeasuredWidth ();
|
||||
}
|
||||
|
||||
/* Now set the measured size of this widget. */
|
||||
setMeasuredDimension (width, y + height);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void
|
||||
onLayout (boolean changed, int left, int top, int right,
|
||||
int bottom)
|
||||
{
|
||||
int width, count, i, x, y, height, spec, tempSpec;
|
||||
View view;
|
||||
|
||||
/* Obtain the width of this widget and create the measure
|
||||
specification used to measure children. */
|
||||
|
||||
width = getMeasuredWidth ();
|
||||
spec = MeasureSpec.makeMeasureSpec (0, MeasureSpec.UNSPECIFIED);
|
||||
tempSpec
|
||||
= MeasureSpec.makeMeasureSpec (width, MeasureSpec.AT_MOST);
|
||||
x = y = height = 0;
|
||||
|
||||
/* Run through each widget. */
|
||||
|
||||
count = getChildCount ();
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
{
|
||||
view = getChildAt (i);
|
||||
|
||||
/* Measure this view. */
|
||||
view.measure (spec, spec);
|
||||
|
||||
if (width - x < view.getMeasuredWidth ())
|
||||
{
|
||||
/* Move onto the next line, unless this line is empty. */
|
||||
|
||||
if (x != 0)
|
||||
{
|
||||
y += height;
|
||||
height = x = 0;
|
||||
}
|
||||
|
||||
if (view.getMeasuredWidth () > width)
|
||||
/* Measure the view again, this time forcing it to be at
|
||||
most width wide, if it is not already. */
|
||||
view.measure (tempSpec, spec);
|
||||
}
|
||||
|
||||
/* Now assign this view its position. */
|
||||
view.layout (x, y, x + view.getMeasuredWidth (),
|
||||
y + view.getMeasuredHeight ());
|
||||
|
||||
/* And move on to the next widget. */
|
||||
height = Math.max (height, view.getMeasuredHeight ());
|
||||
x += view.getMeasuredWidth ();
|
||||
}
|
||||
}
|
||||
};
|
33
java/org/gnu/emacs/EmacsDirectoryEntry.java
Normal file
33
java/org/gnu/emacs/EmacsDirectoryEntry.java
Normal file
|
@ -0,0 +1,33 @@
|
|||
/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
|
||||
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
package org.gnu.emacs;
|
||||
|
||||
/* Structure holding a single ``directory entry'' from a document
|
||||
provider. */
|
||||
|
||||
public final class EmacsDirectoryEntry
|
||||
{
|
||||
/* The type of this directory entry. 0 means a regular file and 1
|
||||
means a directory. */
|
||||
public int d_type;
|
||||
|
||||
/* The display name of the file represented. */
|
||||
public String d_name;
|
||||
};
|
578
java/org/gnu/emacs/EmacsDocumentsProvider.java
Normal file
578
java/org/gnu/emacs/EmacsDocumentsProvider.java
Normal file
|
@ -0,0 +1,578 @@
|
|||
/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
|
||||
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
package org.gnu.emacs;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.database.MatrixCursor;
|
||||
|
||||
import android.os.Build;
|
||||
import android.os.CancellationSignal;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
|
||||
import android.provider.DocumentsContract.Document;
|
||||
import android.provider.DocumentsContract.Root;
|
||||
import static android.provider.DocumentsContract.buildChildDocumentsUri;
|
||||
import android.provider.DocumentsProvider;
|
||||
|
||||
import android.webkit.MimeTypeMap;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/* ``Documents provider''. This allows Emacs's home directory to be
|
||||
modified by other programs holding permissions to manage system
|
||||
storage, which is useful to (for example) correct misconfigurations
|
||||
which prevent Emacs from starting up.
|
||||
|
||||
This functionality is only available on Android 19 and later. */
|
||||
|
||||
public final class EmacsDocumentsProvider extends DocumentsProvider
|
||||
{
|
||||
/* Home directory. This is the directory whose contents are
|
||||
initially returned to requesting applications. */
|
||||
private File baseDir;
|
||||
|
||||
/* The default projection for requests for the root directory. */
|
||||
private static final String[] DEFAULT_ROOT_PROJECTION;
|
||||
|
||||
/* The default projection for requests for a file. */
|
||||
private static final String[] DEFAULT_DOCUMENT_PROJECTION;
|
||||
|
||||
static
|
||||
{
|
||||
DEFAULT_ROOT_PROJECTION = new String[] {
|
||||
Root.COLUMN_ROOT_ID,
|
||||
Root.COLUMN_MIME_TYPES,
|
||||
Root.COLUMN_FLAGS,
|
||||
Root.COLUMN_ICON,
|
||||
Root.COLUMN_TITLE,
|
||||
Root.COLUMN_SUMMARY,
|
||||
Root.COLUMN_DOCUMENT_ID,
|
||||
Root.COLUMN_AVAILABLE_BYTES,
|
||||
};
|
||||
|
||||
DEFAULT_DOCUMENT_PROJECTION = new String[] {
|
||||
Document.COLUMN_DOCUMENT_ID,
|
||||
Document.COLUMN_MIME_TYPE,
|
||||
Document.COLUMN_DISPLAY_NAME,
|
||||
Document.COLUMN_LAST_MODIFIED,
|
||||
Document.COLUMN_FLAGS,
|
||||
Document.COLUMN_SIZE,
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean
|
||||
onCreate ()
|
||||
{
|
||||
/* Set the base directory to Emacs's files directory. */
|
||||
baseDir = getContext ().getFilesDir ();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor
|
||||
queryRoots (String[] projection)
|
||||
{
|
||||
MatrixCursor result;
|
||||
MatrixCursor.RowBuilder row;
|
||||
|
||||
/* If the requestor asked for nothing at all, then it wants some
|
||||
data by default. */
|
||||
|
||||
if (projection == null)
|
||||
projection = DEFAULT_ROOT_PROJECTION;
|
||||
|
||||
result = new MatrixCursor (projection);
|
||||
row = result.newRow ();
|
||||
|
||||
/* Now create and add a row for each file in the base
|
||||
directory. */
|
||||
row.add (Root.COLUMN_ROOT_ID, baseDir.getAbsolutePath ());
|
||||
row.add (Root.COLUMN_SUMMARY, "Emacs home directory");
|
||||
|
||||
/* Add the appropriate flags. */
|
||||
|
||||
row.add (Root.COLUMN_FLAGS, (Root.FLAG_SUPPORTS_CREATE
|
||||
| Root.FLAG_SUPPORTS_IS_CHILD));
|
||||
row.add (Root.COLUMN_ICON, R.drawable.emacs);
|
||||
row.add (Root.FLAG_LOCAL_ONLY);
|
||||
row.add (Root.COLUMN_TITLE, "Emacs");
|
||||
row.add (Root.COLUMN_DOCUMENT_ID, baseDir.getAbsolutePath ());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Uri
|
||||
getNotificationUri (File file)
|
||||
{
|
||||
Uri updatedUri;
|
||||
|
||||
updatedUri
|
||||
= buildChildDocumentsUri ("org.gnu.emacs",
|
||||
file.getAbsolutePath ());
|
||||
|
||||
return updatedUri;
|
||||
}
|
||||
|
||||
/* Inform the system that FILE's contents (or FILE itself) has
|
||||
changed. */
|
||||
|
||||
private void
|
||||
notifyChange (File file)
|
||||
{
|
||||
Uri updatedUri;
|
||||
Context context;
|
||||
|
||||
context = getContext ();
|
||||
updatedUri
|
||||
= buildChildDocumentsUri ("org.gnu.emacs",
|
||||
file.getAbsolutePath ());
|
||||
context.getContentResolver ().notifyChange (updatedUri, null);
|
||||
}
|
||||
|
||||
/* Inform the system that FILE's contents (or FILE itself) has
|
||||
changed. FILE is a string describing containing the file name of
|
||||
a directory as opposed to a File. */
|
||||
|
||||
private void
|
||||
notifyChangeByName (String file)
|
||||
{
|
||||
Uri updatedUri;
|
||||
Context context;
|
||||
|
||||
context = getContext ();
|
||||
updatedUri
|
||||
= buildChildDocumentsUri ("org.gnu.emacs", file);
|
||||
context.getContentResolver ().notifyChange (updatedUri, null);
|
||||
}
|
||||
|
||||
/* Return the MIME type of a file FILE. */
|
||||
|
||||
private String
|
||||
getMimeType (File file)
|
||||
{
|
||||
String name, extension, mime;
|
||||
int extensionSeparator;
|
||||
MimeTypeMap singleton;
|
||||
|
||||
if (file.isDirectory ())
|
||||
return Document.MIME_TYPE_DIR;
|
||||
|
||||
/* Abuse WebView stuff to get the file's MIME type. */
|
||||
name = file.getName ();
|
||||
extensionSeparator = name.lastIndexOf ('.');
|
||||
|
||||
if (extensionSeparator > 0)
|
||||
{
|
||||
singleton = MimeTypeMap.getSingleton ();
|
||||
extension = name.substring (extensionSeparator + 1);
|
||||
mime = singleton.getMimeTypeFromExtension (extension);
|
||||
|
||||
if (mime != null)
|
||||
return mime;
|
||||
}
|
||||
|
||||
return "application/octet-stream";
|
||||
}
|
||||
|
||||
/* Append the specified FILE to the query result RESULT.
|
||||
Handle both directories and ordinary files. */
|
||||
|
||||
private void
|
||||
queryDocument1 (MatrixCursor result, File file)
|
||||
{
|
||||
MatrixCursor.RowBuilder row;
|
||||
String fileName, displayName, mimeType;
|
||||
int flags;
|
||||
|
||||
row = result.newRow ();
|
||||
flags = 0;
|
||||
|
||||
/* fileName is a string that the system will ask for some time in
|
||||
the future. Here, it is just the absolute name of the file. */
|
||||
fileName = file.getAbsolutePath ();
|
||||
|
||||
/* If file is a directory, add the right flags for that. */
|
||||
|
||||
if (file.isDirectory ())
|
||||
{
|
||||
if (file.canWrite ())
|
||||
{
|
||||
flags |= Document.FLAG_DIR_SUPPORTS_CREATE;
|
||||
flags |= Document.FLAG_SUPPORTS_DELETE;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
|
||||
flags |= Document.FLAG_SUPPORTS_RENAME;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
|
||||
flags |= Document.FLAG_SUPPORTS_MOVE;
|
||||
}
|
||||
}
|
||||
else if (file.canWrite ())
|
||||
{
|
||||
/* Apply the correct flags for a writable file. */
|
||||
flags |= Document.FLAG_SUPPORTS_WRITE;
|
||||
flags |= Document.FLAG_SUPPORTS_DELETE;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
|
||||
flags |= Document.FLAG_SUPPORTS_RENAME;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
|
||||
{
|
||||
flags |= Document.FLAG_SUPPORTS_REMOVE;
|
||||
flags |= Document.FLAG_SUPPORTS_MOVE;
|
||||
}
|
||||
}
|
||||
|
||||
displayName = file.getName ();
|
||||
mimeType = getMimeType (file);
|
||||
|
||||
row.add (Document.COLUMN_DOCUMENT_ID, fileName);
|
||||
row.add (Document.COLUMN_DISPLAY_NAME, displayName);
|
||||
row.add (Document.COLUMN_SIZE, file.length ());
|
||||
row.add (Document.COLUMN_MIME_TYPE, mimeType);
|
||||
row.add (Document.COLUMN_LAST_MODIFIED, file.lastModified ());
|
||||
row.add (Document.COLUMN_FLAGS, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor
|
||||
queryDocument (String documentId, String[] projection)
|
||||
throws FileNotFoundException
|
||||
{
|
||||
MatrixCursor result;
|
||||
File file;
|
||||
Context context;
|
||||
|
||||
file = new File (documentId);
|
||||
context = getContext ();
|
||||
|
||||
if (projection == null)
|
||||
projection = DEFAULT_DOCUMENT_PROJECTION;
|
||||
|
||||
result = new MatrixCursor (projection);
|
||||
queryDocument1 (result, file);
|
||||
|
||||
/* Now allow interested applications to detect changes. */
|
||||
result.setNotificationUri (context.getContentResolver (),
|
||||
getNotificationUri (file));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor
|
||||
queryChildDocuments (String parentDocumentId, String[] projection,
|
||||
String sortOrder) throws FileNotFoundException
|
||||
{
|
||||
MatrixCursor result;
|
||||
File directory;
|
||||
File[] files;
|
||||
Context context;
|
||||
|
||||
if (projection == null)
|
||||
projection = DEFAULT_DOCUMENT_PROJECTION;
|
||||
|
||||
result = new MatrixCursor (projection);
|
||||
|
||||
/* Try to open the file corresponding to the location being
|
||||
requested. */
|
||||
directory = new File (parentDocumentId);
|
||||
|
||||
/* Look up each child. */
|
||||
files = directory.listFiles ();
|
||||
|
||||
if (files != null)
|
||||
{
|
||||
/* Now add each child. */
|
||||
for (File child : files)
|
||||
queryDocument1 (result, child);
|
||||
}
|
||||
|
||||
context = getContext ();
|
||||
|
||||
/* Now allow interested applications to detect changes. */
|
||||
result.setNotificationUri (context.getContentResolver (),
|
||||
getNotificationUri (directory));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParcelFileDescriptor
|
||||
openDocument (String documentId, String mode,
|
||||
CancellationSignal signal) throws FileNotFoundException
|
||||
{
|
||||
return ParcelFileDescriptor.open (new File (documentId),
|
||||
ParcelFileDescriptor.parseMode (mode));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String
|
||||
createDocument (String documentId, String mimeType,
|
||||
String displayName) throws FileNotFoundException
|
||||
{
|
||||
File file, parentFile;
|
||||
boolean rc;
|
||||
|
||||
file = new File (documentId, displayName);
|
||||
|
||||
try
|
||||
{
|
||||
rc = false;
|
||||
|
||||
if (Document.MIME_TYPE_DIR.equals (mimeType))
|
||||
{
|
||||
file.mkdirs ();
|
||||
|
||||
if (file.isDirectory ())
|
||||
rc = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
file.createNewFile ();
|
||||
|
||||
if (file.isFile ()
|
||||
&& file.setWritable (true)
|
||||
&& file.setReadable (true))
|
||||
rc = true;
|
||||
}
|
||||
|
||||
if (!rc)
|
||||
throw new FileNotFoundException ("rc != 1");
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new FileNotFoundException (e.toString ());
|
||||
}
|
||||
|
||||
parentFile = file.getParentFile ();
|
||||
|
||||
if (parentFile != null)
|
||||
notifyChange (parentFile);
|
||||
|
||||
return file.getAbsolutePath ();
|
||||
}
|
||||
|
||||
private void
|
||||
deleteDocument1 (File child)
|
||||
{
|
||||
File[] children;
|
||||
|
||||
/* Don't delete symlinks recursively.
|
||||
|
||||
Calling readlink or stat is problematic due to file name
|
||||
encoding problems, so try to delete the file first, and only
|
||||
try to delete files recursively afterword. */
|
||||
|
||||
if (child.delete ())
|
||||
return;
|
||||
|
||||
children = child.listFiles ();
|
||||
|
||||
if (children != null)
|
||||
{
|
||||
for (File file : children)
|
||||
deleteDocument1 (file);
|
||||
}
|
||||
|
||||
child.delete ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void
|
||||
deleteDocument (String documentId)
|
||||
throws FileNotFoundException
|
||||
{
|
||||
File file, parent;
|
||||
File[] children;
|
||||
|
||||
/* Java makes recursively deleting a file hard. File name
|
||||
encoding issues also prevent easily calling into C... */
|
||||
|
||||
file = new File (documentId);
|
||||
parent = file.getParentFile ();
|
||||
|
||||
if (parent == null)
|
||||
throw new RuntimeException ("trying to delete file without"
|
||||
+ " parent!");
|
||||
|
||||
if (file.delete ())
|
||||
{
|
||||
/* Tell the system about the change. */
|
||||
notifyChange (parent);
|
||||
return;
|
||||
}
|
||||
|
||||
children = file.listFiles ();
|
||||
|
||||
if (children != null)
|
||||
{
|
||||
for (File child : children)
|
||||
deleteDocument1 (child);
|
||||
}
|
||||
|
||||
if (file.delete ())
|
||||
/* Tell the system about the change. */
|
||||
notifyChange (parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void
|
||||
removeDocument (String documentId, String parentDocumentId)
|
||||
throws FileNotFoundException
|
||||
{
|
||||
deleteDocument (documentId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String
|
||||
getDocumentType (String documentId)
|
||||
{
|
||||
return getMimeType (new File (documentId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String
|
||||
renameDocument (String documentId, String displayName)
|
||||
throws FileNotFoundException
|
||||
{
|
||||
File file, newName;
|
||||
File parent;
|
||||
|
||||
file = new File (documentId);
|
||||
parent = file.getParentFile ();
|
||||
newName = new File (parent, displayName);
|
||||
|
||||
if (parent == null)
|
||||
throw new FileNotFoundException ("parent is null");
|
||||
|
||||
file = new File (documentId);
|
||||
|
||||
if (!file.renameTo (newName))
|
||||
return null;
|
||||
|
||||
notifyChange (parent);
|
||||
return newName.getAbsolutePath ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean
|
||||
isChildDocument (String parentDocumentId, String documentId)
|
||||
{
|
||||
return documentId.startsWith (parentDocumentId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String
|
||||
moveDocument (String sourceDocumentId,
|
||||
String sourceParentDocumentId,
|
||||
String targetParentDocumentId)
|
||||
throws FileNotFoundException
|
||||
{
|
||||
File file, newName;
|
||||
FileInputStream inputStream;
|
||||
FileOutputStream outputStream;
|
||||
byte buffer[];
|
||||
int length;
|
||||
|
||||
file = new File (sourceDocumentId);
|
||||
|
||||
/* Now, create the file name of the parent document. */
|
||||
newName = new File (targetParentDocumentId,
|
||||
file.getName ());
|
||||
|
||||
/* Try to perform a simple rename, before falling back to
|
||||
copying. */
|
||||
|
||||
if (file.renameTo (newName))
|
||||
{
|
||||
notifyChangeByName (file.getParent ());
|
||||
notifyChangeByName (targetParentDocumentId);
|
||||
return newName.getAbsolutePath ();
|
||||
}
|
||||
|
||||
/* If that doesn't work, create the new file and copy over the old
|
||||
file's contents. */
|
||||
|
||||
inputStream = null;
|
||||
outputStream = null;
|
||||
|
||||
try
|
||||
{
|
||||
if (!newName.createNewFile ()
|
||||
|| !newName.setWritable (true)
|
||||
|| !newName.setReadable (true))
|
||||
throw new FileNotFoundException ("failed to create new file");
|
||||
|
||||
/* Open the file in preparation for a copy. */
|
||||
|
||||
inputStream = new FileInputStream (file);
|
||||
outputStream = new FileOutputStream (newName);
|
||||
|
||||
/* Allocate the buffer used to hold data. */
|
||||
|
||||
buffer = new byte[4096];
|
||||
|
||||
while ((length = inputStream.read (buffer)) > 0)
|
||||
outputStream.write (buffer, 0, length);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new FileNotFoundException ("IOException: " + e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
if (inputStream != null)
|
||||
inputStream.close ();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (outputStream != null)
|
||||
outputStream.close ();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
file.delete ();
|
||||
notifyChangeByName (file.getParent ());
|
||||
notifyChangeByName (targetParentDocumentId);
|
||||
|
||||
return newName.getAbsolutePath ();
|
||||
}
|
||||
}
|
79
java/org/gnu/emacs/EmacsDrawLine.java
Normal file
79
java/org/gnu/emacs/EmacsDrawLine.java
Normal file
|
@ -0,0 +1,79 @@
|
|||
/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
|
||||
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
package org.gnu.emacs;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
|
||||
public final class EmacsDrawLine
|
||||
{
|
||||
public static void
|
||||
perform (EmacsDrawable drawable, EmacsGC gc,
|
||||
int x, int y, int x2, int y2)
|
||||
{
|
||||
Rect rect;
|
||||
Canvas canvas;
|
||||
Paint paint;
|
||||
int x0, x1, y0, y1;
|
||||
|
||||
/* TODO implement stippling. */
|
||||
if (gc.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
|
||||
return;
|
||||
|
||||
/* Calculate the leftmost and rightmost points. */
|
||||
|
||||
x0 = Math.min (x, x2 + 1);
|
||||
x1 = Math.max (x, x2 + 1);
|
||||
y0 = Math.min (y, y2 + 1);
|
||||
y1 = Math.max (y, y2 + 1);
|
||||
|
||||
/* And the clip rectangle. */
|
||||
|
||||
paint = gc.gcPaint;
|
||||
rect = new Rect (x0, y0, x1, y1);
|
||||
canvas = drawable.lockCanvas (gc);
|
||||
|
||||
if (canvas == null)
|
||||
return;
|
||||
|
||||
paint.setStyle (Paint.Style.FILL);
|
||||
|
||||
/* Since drawLine has PostScript style behavior, adjust the
|
||||
coordinates appropriately.
|
||||
|
||||
The left most pixel of a straight line is always partially
|
||||
filled. Patch it in manually. */
|
||||
|
||||
if (gc.clip_mask == null)
|
||||
{
|
||||
canvas.drawLine ((float) x + 0.5f, (float) y + 0.5f,
|
||||
(float) x2 + 0.5f, (float) y2 + 0.5f,
|
||||
paint);
|
||||
|
||||
if (x2 > x)
|
||||
canvas.drawRect (new Rect (x, y, x + 1, y + 1), paint);
|
||||
}
|
||||
|
||||
/* DrawLine with clip mask not implemented; it is not used by
|
||||
Emacs. */
|
||||
drawable.damageRect (rect);
|
||||
}
|
||||
}
|
34
java/org/gnu/emacs/EmacsDrawPoint.java
Normal file
34
java/org/gnu/emacs/EmacsDrawPoint.java
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
|
||||
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
package org.gnu.emacs;
|
||||
|
||||
public final class EmacsDrawPoint
|
||||
{
|
||||
public static void
|
||||
perform (EmacsDrawable drawable,
|
||||
EmacsGC immutableGC, int x, int y)
|
||||
{
|
||||
/* Use EmacsFillRectangle instead of EmacsDrawRectangle, as the
|
||||
latter actually draws a rectangle one pixel wider than
|
||||
specified. */
|
||||
EmacsFillRectangle.perform (drawable, immutableGC,
|
||||
x, y, 1, 1);
|
||||
}
|
||||
}
|
120
java/org/gnu/emacs/EmacsDrawRectangle.java
Normal file
120
java/org/gnu/emacs/EmacsDrawRectangle.java
Normal file
|
@ -0,0 +1,120 @@
|
|||
/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
|
||||
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
package org.gnu.emacs;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
public final class EmacsDrawRectangle
|
||||
{
|
||||
public static void
|
||||
perform (EmacsDrawable drawable, EmacsGC gc,
|
||||
int x, int y, int width, int height)
|
||||
{
|
||||
Paint maskPaint, paint;
|
||||
Canvas maskCanvas;
|
||||
Bitmap maskBitmap;
|
||||
Rect maskRect, dstRect;
|
||||
Canvas canvas;
|
||||
Bitmap clipBitmap;
|
||||
|
||||
/* TODO implement stippling. */
|
||||
if (gc.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
|
||||
return;
|
||||
|
||||
canvas = drawable.lockCanvas (gc);
|
||||
|
||||
if (canvas == null)
|
||||
return;
|
||||
|
||||
paint = gc.gcPaint;
|
||||
paint.setStyle (Paint.Style.STROKE);
|
||||
|
||||
if (gc.clip_mask == null)
|
||||
/* Use canvas.drawRect with a RectF. That seems to reliably
|
||||
get PostScript behavior. */
|
||||
canvas.drawRect (new RectF (x + 0.5f, y + 0.5f,
|
||||
x + width + 0.5f,
|
||||
y + height + 0.5f),
|
||||
paint);
|
||||
else
|
||||
{
|
||||
/* Drawing with a clip mask involves calculating the
|
||||
intersection of the clip mask with the dst rect, and
|
||||
extrapolating the corresponding part of the src rect. */
|
||||
clipBitmap = gc.clip_mask.bitmap;
|
||||
dstRect = new Rect (x, y, x + width, y + height);
|
||||
maskRect = new Rect (gc.clip_x_origin,
|
||||
gc.clip_y_origin,
|
||||
(gc.clip_x_origin
|
||||
+ clipBitmap.getWidth ()),
|
||||
(gc.clip_y_origin
|
||||
+ clipBitmap.getHeight ()));
|
||||
|
||||
if (!maskRect.setIntersect (dstRect, maskRect))
|
||||
/* There is no intersection between the clip mask and the
|
||||
dest rect. */
|
||||
return;
|
||||
|
||||
/* Finally, create a temporary bitmap that is the size of
|
||||
maskRect. */
|
||||
|
||||
maskBitmap
|
||||
= Bitmap.createBitmap (maskRect.width (), maskRect.height (),
|
||||
Bitmap.Config.ARGB_8888);
|
||||
|
||||
/* Draw the mask onto the maskBitmap. */
|
||||
maskCanvas = new Canvas (maskBitmap);
|
||||
maskRect.offset (-gc.clip_x_origin,
|
||||
-gc.clip_y_origin);
|
||||
maskCanvas.drawBitmap (gc.clip_mask.bitmap,
|
||||
maskRect, new Rect (0, 0,
|
||||
maskRect.width (),
|
||||
maskRect.height ()),
|
||||
paint);
|
||||
maskRect.offset (gc.clip_x_origin,
|
||||
gc.clip_y_origin);
|
||||
|
||||
/* Set the transfer mode to SRC_IN to preserve only the parts
|
||||
of the source that overlap with the mask. */
|
||||
maskPaint = new Paint ();
|
||||
maskPaint.setXfermode (EmacsGC.srcInAlu);
|
||||
maskPaint.setStyle (Paint.Style.STROKE);
|
||||
|
||||
/* Draw the source. */
|
||||
maskCanvas.drawRect (maskRect, maskPaint);
|
||||
|
||||
/* Finally, draw the mask bitmap to the destination. */
|
||||
paint.setXfermode (null);
|
||||
canvas.drawBitmap (maskBitmap, null, maskRect, paint);
|
||||
|
||||
/* Recycle this unused bitmap. */
|
||||
maskBitmap.recycle ();
|
||||
}
|
||||
|
||||
drawable.damageRect (new Rect (x, y, x + width + 1,
|
||||
y + height + 1));
|
||||
}
|
||||
}
|
32
java/org/gnu/emacs/EmacsDrawable.java
Normal file
32
java/org/gnu/emacs/EmacsDrawable.java
Normal file
|
@ -0,0 +1,32 @@
|
|||
/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
|
||||
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
package org.gnu.emacs;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
|
||||
public interface EmacsDrawable
|
||||
{
|
||||
public Canvas lockCanvas (EmacsGC gc);
|
||||
public void damageRect (Rect damageRect);
|
||||
public Bitmap getBitmap ();
|
||||
public boolean isDestroyed ();
|
||||
};
|
80
java/org/gnu/emacs/EmacsFillPolygon.java
Normal file
80
java/org/gnu/emacs/EmacsFillPolygon.java
Normal file
|
@ -0,0 +1,80 @@
|
|||
/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
|
||||
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
package org.gnu.emacs;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
|
||||
public final class EmacsFillPolygon
|
||||
{
|
||||
public static void
|
||||
perform (EmacsDrawable drawable, EmacsGC gc, Point points[])
|
||||
{
|
||||
Canvas canvas;
|
||||
Path path;
|
||||
Paint paint;
|
||||
Rect rect;
|
||||
RectF rectF;
|
||||
int i;
|
||||
|
||||
canvas = drawable.lockCanvas (gc);
|
||||
|
||||
if (canvas == null)
|
||||
return;
|
||||
|
||||
paint = gc.gcPaint;
|
||||
|
||||
/* Build the path from the given array of points. */
|
||||
path = new Path ();
|
||||
|
||||
if (points.length >= 1)
|
||||
{
|
||||
path.moveTo (points[0].x, points[0].y);
|
||||
|
||||
for (i = 1; i < points.length; ++i)
|
||||
path.lineTo (points[i].x, points[i].y);
|
||||
|
||||
path.close ();
|
||||
}
|
||||
|
||||
/* Compute the damage rectangle. */
|
||||
rectF = new RectF (0, 0, 0, 0);
|
||||
path.computeBounds (rectF, true);
|
||||
|
||||
rect = new Rect ((int) Math.floor (rectF.left),
|
||||
(int) Math.floor (rectF.top),
|
||||
(int) Math.ceil (rectF.right),
|
||||
(int) Math.ceil (rectF.bottom));
|
||||
|
||||
paint.setStyle (Paint.Style.FILL);
|
||||
|
||||
if (gc.clip_mask == null)
|
||||
canvas.drawPath (path, paint);
|
||||
|
||||
drawable.damageRect (rect);
|
||||
|
||||
/* FillPolygon with clip mask not implemented; it is not used by
|
||||
Emacs. */
|
||||
}
|
||||
}
|
116
java/org/gnu/emacs/EmacsFillRectangle.java
Normal file
116
java/org/gnu/emacs/EmacsFillRectangle.java
Normal file
|
@ -0,0 +1,116 @@
|
|||
/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
|
||||
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
package org.gnu.emacs;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
public final class EmacsFillRectangle
|
||||
{
|
||||
public static void
|
||||
perform (EmacsDrawable drawable, EmacsGC gc,
|
||||
int x, int y, int width, int height)
|
||||
{
|
||||
Paint maskPaint, paint;
|
||||
Canvas maskCanvas;
|
||||
Bitmap maskBitmap;
|
||||
Rect rect;
|
||||
Rect maskRect, dstRect;
|
||||
Canvas canvas;
|
||||
Bitmap clipBitmap;
|
||||
|
||||
/* TODO implement stippling. */
|
||||
if (gc.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
|
||||
return;
|
||||
|
||||
canvas = drawable.lockCanvas (gc);
|
||||
|
||||
if (canvas == null)
|
||||
return;
|
||||
|
||||
paint = gc.gcPaint;
|
||||
rect = new Rect (x, y, x + width, y + height);
|
||||
|
||||
paint.setStyle (Paint.Style.FILL);
|
||||
|
||||
if (gc.clip_mask == null)
|
||||
canvas.drawRect (rect, paint);
|
||||
else
|
||||
{
|
||||
/* Drawing with a clip mask involves calculating the
|
||||
intersection of the clip mask with the dst rect, and
|
||||
extrapolating the corresponding part of the src rect. */
|
||||
|
||||
clipBitmap = gc.clip_mask.bitmap;
|
||||
dstRect = new Rect (x, y, x + width, y + height);
|
||||
maskRect = new Rect (gc.clip_x_origin,
|
||||
gc.clip_y_origin,
|
||||
(gc.clip_x_origin
|
||||
+ clipBitmap.getWidth ()),
|
||||
(gc.clip_y_origin
|
||||
+ clipBitmap.getHeight ()));
|
||||
|
||||
if (!maskRect.setIntersect (dstRect, maskRect))
|
||||
/* There is no intersection between the clip mask and the
|
||||
dest rect. */
|
||||
return;
|
||||
|
||||
/* Finally, create a temporary bitmap that is the size of
|
||||
maskRect. */
|
||||
|
||||
maskBitmap
|
||||
= Bitmap.createBitmap (maskRect.width (), maskRect.height (),
|
||||
Bitmap.Config.ARGB_8888);
|
||||
|
||||
/* Draw the mask onto the maskBitmap. */
|
||||
maskCanvas = new Canvas (maskBitmap);
|
||||
maskRect.offset (-gc.clip_x_origin,
|
||||
-gc.clip_y_origin);
|
||||
maskCanvas.drawBitmap (gc.clip_mask.bitmap,
|
||||
maskRect, new Rect (0, 0,
|
||||
maskRect.width (),
|
||||
maskRect.height ()),
|
||||
paint);
|
||||
maskRect.offset (gc.clip_x_origin,
|
||||
gc.clip_y_origin);
|
||||
|
||||
/* Set the transfer mode to SRC_IN to preserve only the parts
|
||||
of the source that overlap with the mask. */
|
||||
maskPaint = new Paint ();
|
||||
maskPaint.setXfermode (EmacsGC.srcInAlu);
|
||||
|
||||
/* Draw the source. */
|
||||
maskCanvas.drawRect (maskRect, maskPaint);
|
||||
|
||||
/* Finally, draw the mask bitmap to the destination. */
|
||||
paint.setXfermode (null);
|
||||
canvas.drawBitmap (maskBitmap, null, maskRect, paint);
|
||||
|
||||
/* Recycle this unused bitmap. */
|
||||
maskBitmap.recycle ();
|
||||
}
|
||||
|
||||
drawable.damageRect (rect);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue