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:
Po Lu 2023-08-07 08:51:11 +08:00
commit c71a520d1d
293 changed files with 105609 additions and 1281 deletions

View file

@ -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
View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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.

View file

@ -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
View file

@ -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

View file

@ -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 \

View file

@ -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
View 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

View 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)

View 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)

View 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)

View 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

View 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:

View 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 = ""
}

File diff suppressed because it is too large Load diff

190
cross/Makefile.in Normal file
View 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
View 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
View 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
View 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
View 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/>.

View 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

View 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))))

View 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 $@ $^

View 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)

View 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 :=

View 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)

View 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)

View 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
View 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

View file

@ -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
View 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.

View file

@ -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

View file

@ -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

View file

@ -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
View 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.

View file

@ -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

View file

@ -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:

View file

@ -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

View file

@ -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.

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -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

View file

@ -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.

View file

@ -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

View file

@ -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
+++

View file

@ -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

Binary file not shown.

BIN
etc/images/ctrl.pbm Normal file

Binary file not shown.

BIN
etc/images/hyper.pbm Normal file

Binary file not shown.

BIN
etc/images/last-page.pbm Normal file

Binary file not shown.

122
etc/images/last-page.xpm Normal file
View 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

Binary file not shown.

BIN
etc/images/shift.pbm Normal file

Binary file not shown.

BIN
etc/images/super.pbm Normal file

Binary file not shown.

140
exec/Makefile.in Normal file
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

358
exec/config.h.in Normal file
View 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

File diff suppressed because it is too large Load diff

537
exec/configure.ac Normal file
View 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
View 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

File diff suppressed because it is too large Load diff

201
exec/exec.h Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

225
java/AndroidManifest.xml.in Normal file
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

368
java/debug.sh Executable file
View 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

Binary file not shown.

View 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;
}
}
};

View 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 ();
}
};

View 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 ();
}
};

View 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;
}
});
}
};

View 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);
}
};

View 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);
}
};

View 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 ();
}
}
};

View 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;
};

View 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 ();
}
}

View 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);
}
}

View 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);
}
}

View 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));
}
}

View 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 ();
};

View 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. */
}
}

View 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