From cedc19297e47473ae599faa7cbcb2f3f6c9d5846 Mon Sep 17 00:00:00 2001 From: Andrea Corallo Date: Tue, 24 Dec 2019 22:26:20 +0100 Subject: add elns to the gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) (limited to '.gitignore') diff --git a/.gitignore b/.gitignore index d4be6bb23eb..52816e8473f 100644 --- a/.gitignore +++ b/.gitignore @@ -132,6 +132,7 @@ src/gl-stamp *.dll *.core *.elc +*.eln *.o *.res *.so -- cgit v1.2.3 From 2a9ce136eda80297ce53eed4333d1c98bffaa21a Mon Sep 17 00:00:00 2001 From: Lars Ingebrigtsen Date: Sat, 27 Feb 2021 05:23:45 +0100 Subject: Add generated .texi files to .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) (limited to '.gitignore') diff --git a/.gitignore b/.gitignore index dd4eab759cb..ba8a65547f3 100644 --- a/.gitignore +++ b/.gitignore @@ -253,6 +253,8 @@ doc/*/*/*.ps doc/emacs/emacsver.texi doc/man/emacs.1 doc/misc/cc-mode.ss +doc/misc/modus-themes.texi +doc/misc/org.texi etc/DOC etc/refcards/emacsver.tex gnustmp* -- cgit v1.2.3 From d632622b5aac5ff776e1b5048f29aeaf3ceaf553 Mon Sep 17 00:00:00 2001 From: Glenn Morris Date: Sat, 6 Mar 2021 16:28:46 -0800 Subject: Simplify silent-rules build machinery * src/verbose.mk.in: New file. * configure.ac (AM_V, AM_DEFAULT_V): Remove output variables. (src/verbose.mk): New output file. * Makefile.in, admin/charsets/Makefile.in: * admin/grammars/Makefile.in, admin/unidata/Makefile.in: * doc/emacs/Makefile.in, doc/lispintro/Makefile.in: * doc/lispref/Makefile.in, doc/misc/Makefile.in, leim/Makefile.in: * lib-src/Makefile.in, lib/Makefile.in, lisp/Makefile.in: * lwlib/Makefile.in, nt/Makefile.in, oldXMenu/Makefile.in: * src/Makefile.in, src/verbose.mk.in, test/Makefile.in: Include src/verbose.mk rather than repeatedly defining AM_V_at etc. --- .gitignore | 1 + Makefile.in | 14 ++------------ admin/charsets/Makefile.in | 12 ++---------- admin/grammars/Makefile.in | 13 +------------ admin/unidata/Makefile.in | 18 +----------------- configure.ac | 8 +------- doc/emacs/Makefile.in | 10 +++------- doc/lispintro/Makefile.in | 9 ++------- doc/lispref/Makefile.in | 9 ++------- doc/misc/Makefile.in | 10 +++------- leim/Makefile.in | 14 ++------------ lib-src/Makefile.in | 29 ++--------------------------- lib/Makefile.in | 21 +-------------------- lisp/Makefile.in | 20 ++------------------ lwlib/Makefile.in | 19 ++----------------- nt/Makefile.in | 19 ++----------------- oldXMenu/Makefile.in | 19 ++----------------- src/Makefile.in | 36 +++--------------------------------- src/verbose.mk.in | 42 ++++++++++++++++++++++++++++++++++++++++++ test/Makefile.in | 26 ++------------------------ 20 files changed, 78 insertions(+), 271 deletions(-) create mode 100644 src/verbose.mk.in (limited to '.gitignore') diff --git a/.gitignore b/.gitignore index ba8a65547f3..b653ef215b9 100644 --- a/.gitignore +++ b/.gitignore @@ -76,6 +76,7 @@ lib/unistd.h src/buildobj.h src/globals.h src/lisp.mk +src/verbose.mk # Lisp-level sources built by 'make'. *cus-load.el diff --git a/Makefile.in b/Makefile.in index 46373190a6f..6acf9791ab9 100644 --- a/Makefile.in +++ b/Makefile.in @@ -95,18 +95,8 @@ configuration=@configuration@ ### The nt/ subdirectory gets built only for MinGW NTDIR=@NTDIR@ -# 'make' verbosity. -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ - -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = - -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = +top_builddir = @top_builddir@ +-include ${top_builddir}/src/verbose.mk # ==================== Where To Install Things ==================== diff --git a/admin/charsets/Makefile.in b/admin/charsets/Makefile.in index 0fd130d346e..1fe029984b8 100644 --- a/admin/charsets/Makefile.in +++ b/admin/charsets/Makefile.in @@ -31,6 +31,7 @@ AWK = @AWK@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ +top_builddir = @top_builddir@ charsetdir = ${top_srcdir}/etc/charsets lispintdir = ${top_srcdir}/lisp/international @@ -38,16 +39,7 @@ mapfiledir = ${srcdir}/mapfiles GLIBC_CHARMAPS = ${srcdir}/glibc -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = - -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = +-include ${top_builddir}/src/verbose.mk # Note: We can not prepend "ISO-" to these map files because of file # name limits on DOS. diff --git a/admin/grammars/Makefile.in b/admin/grammars/Makefile.in index 98c9c623abc..aa09d9edf94 100644 --- a/admin/grammars/Makefile.in +++ b/admin/grammars/Makefile.in @@ -28,18 +28,7 @@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ -# 'make' verbosity. -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ - -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = - -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = +-include ${top_builddir}/src/verbose.mk # Prevent any settings in the user environment causing problems. unexport EMACSDATA EMACSDOC EMACSPATH diff --git a/admin/unidata/Makefile.in b/admin/unidata/Makefile.in index f31e1bb09fd..183569fb9b6 100644 --- a/admin/unidata/Makefile.in +++ b/admin/unidata/Makefile.in @@ -36,23 +36,7 @@ emacs = "${EMACS}" -batch --no-site-file --no-site-lisp lparen = ( unifiles = $(addprefix ${unidir}/,$(sort $(shell sed -n 's/^[ \t][ \t]*${lparen}"\(uni-[^"]*\)"$$/\1/p' ${srcdir}/unidata-gen.el))) -# 'make' verbosity. -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ - -AM_V_ELC = $(am__v_ELC_@AM_V@) -am__v_ELC_ = $(am__v_ELC_@AM_DEFAULT_V@) -am__v_ELC_0 = @echo " ELC " $@; -am__v_ELC_1 = - -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = - -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = +-include ${top_builddir}/src/verbose.mk .PHONY: all diff --git a/configure.ac b/configure.ac index 385a126dd39..1802c1baa12 100644 --- a/configure.ac +++ b/configure.ac @@ -1184,9 +1184,6 @@ AC_DEFUN([AM_CONDITIONAL], dnl Prefer silent make output. For verbose output, use dnl 'configure --disable-silent-rules' or 'make V=1' . -dnl This code is adapted from Automake. -dnl Although it can be simplified now that GNU Make is assumed, -dnl the simplification hasn't been done yet. AC_ARG_ENABLE([silent-rules], [AS_HELP_STRING( [--disable-silent-rules], @@ -1196,11 +1193,8 @@ if test "$enable_silent_rules" = no; then else AM_DEFAULT_VERBOSITY=0 fi -AM_V='$(V)' -AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' -AC_SUBST([AM_V]) -AC_SUBST([AM_DEFAULT_V]) AC_SUBST([AM_DEFAULT_VERBOSITY]) +AC_CONFIG_FILES([src/verbose.mk]) dnl Some other nice autoconf tests. AC_PROG_INSTALL diff --git a/doc/emacs/Makefile.in b/doc/emacs/Makefile.in index 2a3f53f740d..4585b2e0ddc 100644 --- a/doc/emacs/Makefile.in +++ b/doc/emacs/Makefile.in @@ -28,6 +28,8 @@ srcdir=@srcdir@ top_srcdir = @top_srcdir@ +top_builddir = @top_builddir@ + version = @version@ ## Where the output files go. @@ -73,13 +75,7 @@ TEXI2DVI = texi2dvi TEXI2PDF = texi2pdf DVIPS = dvips -# 'make' verbosity. -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ - -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = +-include ${top_builddir}/src/verbose.mk ENVADD = $(AM_V_GEN)TEXINPUTS="$(srcdir):$(texinfodir):$(TEXINPUTS)" \ MAKEINFO="$(MAKEINFO) $(MAKEINFO_OPTS)" diff --git a/doc/lispintro/Makefile.in b/doc/lispintro/Makefile.in index d8b909c9c10..45b4fe7e3b7 100644 --- a/doc/lispintro/Makefile.in +++ b/doc/lispintro/Makefile.in @@ -20,6 +20,7 @@ SHELL = @SHELL@ srcdir = @srcdir@ +top_builddir = @top_builddir@ buildinfodir = $(srcdir)/../../info # Directory with the (customized) texinfo.tex file. @@ -55,13 +56,7 @@ TEXI2DVI = texi2dvi TEXI2PDF = texi2pdf DVIPS = dvips -# 'make' verbosity. -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ - -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = +-include ${top_builddir}/src/verbose.mk ENVADD = \ $(AM_V_GEN)TEXINPUTS="$(srcdir):$(texinfodir):$(emacsdir):$(TEXINPUTS)" \ diff --git a/doc/lispref/Makefile.in b/doc/lispref/Makefile.in index 271f06edddc..876303593ce 100644 --- a/doc/lispref/Makefile.in +++ b/doc/lispref/Makefile.in @@ -24,6 +24,7 @@ SHELL = @SHELL@ # Standard configure variables. srcdir = @srcdir@ +top_builddir = @top_builddir@ buildinfodir = $(srcdir)/../../info # Directory with the (customized) texinfo.tex file. @@ -59,13 +60,7 @@ TEXI2DVI = texi2dvi TEXI2PDF = texi2pdf DVIPS = dvips -# 'make' verbosity. -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ - -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = +-include ${top_builddir}/src/verbose.mk ENVADD = \ $(AM_V_GEN)TEXINPUTS="$(srcdir):$(texinfodir):$(emacsdir):$(TEXINPUTS)" \ diff --git a/doc/misc/Makefile.in b/doc/misc/Makefile.in index 87d87bf2005..5130650fefe 100644 --- a/doc/misc/Makefile.in +++ b/doc/misc/Makefile.in @@ -23,6 +23,8 @@ SHELL = @SHELL@ # of the source tree. This is set by configure's '--srcdir' option. srcdir=@srcdir@ +top_builddir = @top_builddir@ + ## Where the output files go. ## Note that all the Info targets build the Info files in srcdir. ## There is no provision for Info files to exist in the build directory. @@ -112,13 +114,7 @@ TEXI2DVI = texi2dvi TEXI2PDF = texi2pdf DVIPS = dvips -# 'make' verbosity. -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ - -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = +-include ${top_builddir}/src/verbose.mk ENVADD = $(AM_V_GEN)TEXINPUTS="$(srcdir):$(emacsdir):$(TEXINPUTS)" \ MAKEINFO="$(MAKEINFO) $(MAKEINFO_OPTS)" diff --git a/leim/Makefile.in b/leim/Makefile.in index f3e530a11de..c2f9cf5ab5f 100644 --- a/leim/Makefile.in +++ b/leim/Makefile.in @@ -25,24 +25,14 @@ SHELL = @SHELL@ # Here are the things that we expect ../configure to edit. srcdir=@srcdir@ +top_builddir = @top_builddir@ # Where the generated files go. leimdir = ${srcdir}/../lisp/leim EXEEXT = @EXEEXT@ -# 'make' verbosity. -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ - -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = - -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = +-include ${top_builddir}/src/verbose.mk # Prevent any settings in the user environment causing problems. unexport EMACSDATA EMACSDOC EMACSPATH diff --git a/lib-src/Makefile.in b/lib-src/Makefile.in index 0a6dd826c10..05eb524d19b 100644 --- a/lib-src/Makefile.in +++ b/lib-src/Makefile.in @@ -44,33 +44,8 @@ WERROR_CFLAGS = @WERROR_CFLAGS@ # Program name transformation. TRANSFORM = @program_transform_name@ -# 'make' verbosity. -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ - -AM_V_CC = $(am__v_CC_@AM_V@) -am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) -am__v_CC_0 = @echo " CC " $@; -am__v_CC_1 = - -AM_V_CCLD = $(am__v_CCLD_@AM_V@) -am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) -am__v_CCLD_0 = @echo " CCLD " $@; -am__v_CCLD_1 = - -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = - -AM_V_RC = $(am__v_RC_@AM_V@) -am__v_RC_ = $(am__v_RC_@AM_DEFAULT_V@) -am__v_RC_0 = @echo " RC " $@; -am__v_RC_1 = - -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = +top_builddir = @top_builddir@ +-include ${top_builddir}/src/verbose.mk # ==================== Where To Install Things ==================== diff --git a/lib/Makefile.in b/lib/Makefile.in index 91a6b5ff3f1..043ace29fd7 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -29,26 +29,7 @@ top_srcdir = @top_srcdir@ all: .PHONY: all -# 'make' verbosity. -AM_V_AR = $(am__v_AR_@AM_V@) -am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) -am__v_AR_0 = @echo " AR " $@; -am__v_AR_1 = - -AM_V_CC = $(am__v_CC_@AM_V@) -am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) -am__v_CC_0 = @echo " CC " $@; -am__v_CC_1 = - -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = - -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = +-include ${top_builddir}/src/verbose.mk ALL_CFLAGS= \ $(C_SWITCH_SYSTEM) $(C_SWITCH_MACHINE) $(DEPFLAGS) \ diff --git a/lisp/Makefile.in b/lisp/Makefile.in index 72f7f1676b7..8ea28415585 100644 --- a/lisp/Makefile.in +++ b/lisp/Makefile.in @@ -21,6 +21,7 @@ SHELL = @SHELL@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ +top_builddir = @top_builddir@ lisp = $(srcdir) VPATH = $(srcdir) EXEEXT = @EXEEXT@ @@ -29,24 +30,7 @@ EXEEXT = @EXEEXT@ # limitation. XARGS_LIMIT = @XARGS_LIMIT@ -# 'make' verbosity. -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ - -AM_V_ELC = $(am__v_ELC_@AM_V@) -am__v_ELC_ = $(am__v_ELC_@AM_DEFAULT_V@) -am__v_ELC_0 = @echo " ELC " $@; -am__v_ELC_1 = - -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = - -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = - +-include ${top_builddir}/src/verbose.mk FIND_DELETE = @FIND_DELETE@ diff --git a/lwlib/Makefile.in b/lwlib/Makefile.in index 28c16acbabc..fb0ae0e1c21 100644 --- a/lwlib/Makefile.in +++ b/lwlib/Makefile.in @@ -26,6 +26,7 @@ all: liblw.a .PHONY: all srcdir=@srcdir@ +top_builddir=@top_builddir@ # MinGW CPPFLAGS may use this. abs_top_srcdir=@abs_top_srcdir@ VPATH=@srcdir@ @@ -56,23 +57,7 @@ TOOLKIT_OBJS = $(@X_TOOLKIT_TYPE@_OBJS) OBJS = lwlib.o $(TOOLKIT_OBJS) lwlib-utils.o -# 'make' verbosity. -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ - -AM_V_CC = $(am__v_CC_@AM_V@) -am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) -am__v_CC_0 = @echo " CC " $@; -am__v_CC_1 = - -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = - -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = +-include ${top_builddir}/src/verbose.mk AUTO_DEPEND = @AUTO_DEPEND@ DEPDIR = deps diff --git a/nt/Makefile.in b/nt/Makefile.in index aa3a76280ef..0d448903ba5 100644 --- a/nt/Makefile.in +++ b/nt/Makefile.in @@ -41,23 +41,8 @@ WERROR_CFLAGS = @WERROR_CFLAGS@ # Program name transformation. TRANSFORM = @program_transform_name@ -# 'make' verbosity. -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ - -AM_V_CC = $(am__v_CC_@AM_V@) -am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) -am__v_CC_0 = @echo " CC " $@; -am__v_CC_1 = - -AM_V_CCLD = $(am__v_CCLD_@AM_V@) -am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) -am__v_CCLD_0 = @echo " CCLD " $@; -am__v_CCLD_1 = - -AM_V_RC = $(am__v_RC_@AM_V@) -am__v_RC_ = $(am__v_RC_@AM_DEFAULT_V@) -am__v_RC_0 = @echo " RC " $@; -am__v_RC_1 = +top_builddir = @top_builddir@ +-include ${top_builddir}/src/verbose.mk # ==================== Where To Install Things ==================== diff --git a/oldXMenu/Makefile.in b/oldXMenu/Makefile.in index 7ae355b568d..39fd155735a 100644 --- a/oldXMenu/Makefile.in +++ b/oldXMenu/Makefile.in @@ -43,6 +43,7 @@ ### Code: srcdir=@srcdir@ +top_builddir = @top_builddir@ # MinGW CPPFLAGS may use this. abs_top_srcdir=@abs_top_srcdir@ VPATH=@srcdir@ @@ -93,23 +94,7 @@ OBJS = Activate.o \ all: libXMenu11.a .PHONY: all -# 'make' verbosity. -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ - -AM_V_CC = $(am__v_CC_@AM_V@) -am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) -am__v_CC_0 = @echo " CC " $@; -am__v_CC_1 = - -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = - -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = +-include ${top_builddir}/src/verbose.mk AUTO_DEPEND = @AUTO_DEPEND@ DEPDIR = deps diff --git a/src/Makefile.in b/src/Makefile.in index a5ea5498a49..f3c545dba9a 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -29,6 +29,7 @@ SHELL = @SHELL@ # We use $(srcdir) explicitly in dependencies so as not to depend on VPATH. srcdir = @srcdir@ top_srcdir = @top_srcdir@ +top_builddir = @top_builddir@ # MinGW CPPFLAGS may use this. abs_top_srcdir=@abs_top_srcdir@ VPATH = $(srcdir) @@ -340,33 +341,7 @@ HAVE_PDUMPER = @HAVE_PDUMPER@ ## invalidates the signature, we must re-sign to fix it. DO_CODESIGN=$(patsubst aarch64-apple-darwin%,yes,@configuration@) -# 'make' verbosity. -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ - -AM_V_CC = $(am__v_CC_@AM_V@) -am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) -am__v_CC_0 = @echo " CC " $@; -am__v_CC_1 = - -AM_V_CCLD = $(am__v_CCLD_@AM_V@) -am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) -am__v_CCLD_0 = @echo " CCLD " $@; -am__v_CCLD_1 = - -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = - -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = - -AM_V_NO_PD = $(am__v_NO_PD_@AM_V@) -am__v_NO_PD_ = $(am__v_NO_PD_@AM_DEFAULT_V@) -am__v_NO_PD_0 = --no-print-directory -am__v_NO_PD_1 = +-include ${top_builddir}/src/verbose.mk bootstrap_exe = ../src/bootstrap-emacs$(EXEEXT) ifeq ($(DUMPING),pdumper) @@ -621,11 +596,6 @@ buildobj.h: Makefile GLOBAL_SOURCES = $(base_obj:.o=.c) $(NS_OBJC_OBJ:.o=.m) -AM_V_GLOBALS = $(am__v_GLOBALS_@AM_V@) -am__v_GLOBALS_ = $(am__v_GLOBALS_@AM_DEFAULT_V@) -am__v_GLOBALS_0 = @echo " GEN " globals.h; -am__v_GLOBALS_1 = - gl-stamp: $(libsrc)/make-docfile$(EXEEXT) $(GLOBAL_SOURCES) $(AM_V_GLOBALS)$(libsrc)/make-docfile -d $(srcdir) -g $(obj) > globals.tmp $(AM_V_at)$(top_srcdir)/build-aux/move-if-change globals.tmp globals.h @@ -724,7 +694,7 @@ bootstrap-clean: clean fi distclean: bootstrap-clean - rm -f Makefile lisp.mk + rm -f Makefile lisp.mk verbose.mk rm -fr $(DEPDIR) maintainer-clean: distclean diff --git a/src/verbose.mk.in b/src/verbose.mk.in new file mode 100644 index 00000000000..e55fd63fc3c --- /dev/null +++ b/src/verbose.mk.in @@ -0,0 +1,42 @@ +### verbose.mk --- Makefile fragment for GNU Emacs + +## Copyright (C) 2021 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 . + +# 'make' verbosity. +V = @AM_DEFAULT_VERBOSITY@ +ifeq (${V},1) +AM_V_AR = +AM_V_at = +AM_V_CC = +AM_V_CCLD = +AM_V_ELC = +AM_V_GEN = +AM_V_GLOBALS = +AM_V_NO_PD = +AM_V_RC = +else +AM_V_AR = @echo " AR " $@; +AM_V_at = @ +AM_V_CC = @echo " CC " $@; +AM_V_CCLD = @echo " CCLD " $@; +AM_V_ELC = @echo " ELC " $@; +AM_V_GEN = @echo " GEN " $@; +AM_V_GLOBALS = @echo " GEN " globals.h; +AM_V_NO_PD = --no-print-directory +AM_V_RC = @echo " RC " $@; +endif diff --git a/test/Makefile.in b/test/Makefile.in index 48bbe8712b4..ba354289e28 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -32,6 +32,7 @@ SHELL = @SHELL@ srcdir = @srcdir@ abs_top_srcdir=@abs_top_srcdir@ +top_builddir = @top_builddir@ VPATH = $(srcdir) FIND_DELETE = @FIND_DELETE@ @@ -46,30 +47,7 @@ SO = @MODULES_SUFFIX@ SEPCHAR = @SEPCHAR@ - -# 'make' verbosity. -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ - -AM_V_CCLD = $(am__v_CCLD_@AM_V@) -am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) -am__v_CCLD_0 = @echo " CCLD " $@; -am__v_CCLD_1 = - -AM_V_ELC = $(am__v_ELC_@AM_V@) -am__v_ELC_ = $(am__v_ELC_@AM_DEFAULT_V@) -am__v_ELC_0 = @echo " ELC " $@; -am__v_ELC_1 = - -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = - -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = - +-include ${top_builddir}/src/verbose.mk # Load any GNU ELPA dependencies that are present, for optional tests. GNU_ELPA_DIRECTORY ?= $(srcdir)/../../elpa -- cgit v1.2.3 From 1060289f51ee1bf269bb45940892eb272d35af97 Mon Sep 17 00:00:00 2001 From: Philipp Stephani Date: Thu, 17 Dec 2020 11:20:55 +0100 Subject: Add a helper binary to create a basic Secure Computing filter. The binary uses the 'seccomp' helper library. The library isn't needed to load the generated Secure Computing filter. * configure.ac: Check for 'seccomp' header and library. * lib-src/seccomp-filter.c: New helper binary to generate a generic Secure Computing filter for GNU/Linux. * lib-src/Makefile.in (DONT_INSTALL): Add 'seccomp-filter' helper binary if possible. (all): Add Secure Computing filter file if possible. (seccomp-filter$(EXEEXT)): Compile helper binary. (seccomp-filter.bpf seccomp-filter.pfc): Generate filter files. * test/src/emacs-tests.el (emacs-tests/seccomp/allows-stdout) (emacs-tests/seccomp/forbids-subprocess): New unit tests. * test/Makefile.in (src/emacs-tests.log): Add dependency on the helper binary. --- .gitignore | 5 + configure.ac | 5 + lib-src/Makefile.in | 19 ++ lib-src/seccomp-filter.c | 321 ++++++++++++++++++++++++++++ test/Makefile.in | 2 + test/src/emacs-resources/seccomp-filter.bpf | 1 + test/src/emacs-tests.el | 49 +++++ 7 files changed, 402 insertions(+) create mode 100644 lib-src/seccomp-filter.c create mode 120000 test/src/emacs-resources/seccomp-filter.bpf (limited to '.gitignore') diff --git a/.gitignore b/.gitignore index b653ef215b9..ecf768dc4d6 100644 --- a/.gitignore +++ b/.gitignore @@ -188,6 +188,7 @@ lib-src/make-docfile lib-src/make-fingerprint lib-src/movemail lib-src/profile +lib-src/seccomp-filter lib-src/test-distrib lib-src/update-game-score nextstep/Cocoa/Emacs.base/Contents/Info.plist @@ -301,3 +302,7 @@ nt/emacs.rc nt/emacsclient.rc src/gdb.ini /var/ + +# Seccomp filter files. +lib-src/seccomp-filter.bpf +lib-src/seccomp-filter.pfc diff --git a/configure.ac b/configure.ac index 684788a4d33..0c4772a2b96 100644 --- a/configure.ac +++ b/configure.ac @@ -4181,6 +4181,11 @@ AC_SUBST([LIBS_MAIL]) AC_CHECK_HEADERS([linux/seccomp.h], [HAVE_SECCOMP=yes]) +LIBSECCOMP= +AC_CHECK_HEADER([seccomp.h], + [AC_CHECK_LIB([seccomp], [seccomp_init], [LIBSECCOMP=-lseccomp])]) +AC_SUBST([LIBSECCOMP]) + OLD_LIBS=$LIBS LIBS="$LIB_PTHREAD $LIB_MATH $LIBS" AC_CHECK_FUNCS(accept4 fchdir gethostname \ diff --git a/lib-src/Makefile.in b/lib-src/Makefile.in index 05eb524d19b..1942882004e 100644 --- a/lib-src/Makefile.in +++ b/lib-src/Makefile.in @@ -189,6 +189,12 @@ LIB_WSOCK32=@LIB_WSOCK32@ ## Extra libraries for etags LIBS_ETAGS = $(LIB_CLOCK_GETTIME) $(LIB_GETRANDOM) +LIBSECCOMP=@LIBSECCOMP@ + +ifneq ($(LIBSECCOMP),) +DONT_INSTALL += seccomp-filter$(EXEEXT) +endif + ## Extra libraries to use when linking movemail. LIBS_MOVE = $(LIBS_MAIL) $(KRB4LIB) $(DESLIB) $(KRB5LIB) $(CRYPTOLIB) \ $(COM_ERRLIB) $(LIBHESIOD) $(LIBRESOLV) $(LIB_WSOCK32) $(LIBS_ETAGS) @@ -218,6 +224,10 @@ config_h = ../src/config.h $(srcdir)/../src/conf_post.h all: ${EXE_FILES} ${SCRIPTS} +ifneq ($(LIBSECCOMP),) +all: seccomp-filter.bpf +endif + .PHONY: all need-blessmail maybe-blessmail LOADLIBES = ../lib/libgnu.a $(LIBS_SYSTEM) @@ -400,4 +410,13 @@ update-game-score${EXEEXT}: ${srcdir}/update-game-score.c $(NTLIB) $(config_h) emacsclient.res: ../nt/emacsclient.rc $(NTINC)/../icons/emacs.ico $(AM_V_RC)$(WINDRES) -O coff --include-dir=$(NTINC)/.. -o $@ $< +ifneq ($(LIBSECCOMP),) +seccomp-filter$(EXEEXT): $(srcdir)/seccomp-filter.c $(config_h) + $(AM_V_CCLD)$(CC) $(ALL_CFLAGS) $< $(LIBSECCOMP) -o $@ + +seccomp-filter.bpf seccomp-filter.pfc: seccomp-filter$(EXEEXT) + $(AM_V_GEN)./seccomp-filter$(EXEEXT) \ + seccomp-filter.bpf seccomp-filter.pfc +endif + ## Makefile ends here. diff --git a/lib-src/seccomp-filter.c b/lib-src/seccomp-filter.c new file mode 100644 index 00000000000..9918fb025ef --- /dev/null +++ b/lib-src/seccomp-filter.c @@ -0,0 +1,321 @@ +/* Generate a Secure Computing filter definition file. + +Copyright (C) 2020 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 +. */ + +/* This program creates a small Secure Computing filter usable for a +typical minimal Emacs sandbox. See the man page for `seccomp' for +details about Secure Computing filters. This program requires the +`libseccomp' library. However, the resulting filter file requires +only a Linux kernel supporting the Secure Computing extension. + +Usage: + + seccomp-filter out.bpf out.pfc + +This writes the raw `struct sock_filter' array to out.bpf and a +human-readable representation to out.pfc. */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "verify.h" + +static ATTRIBUTE_FORMAT_PRINTF (2, 3) _Noreturn void +fail (int error, const char *format, ...) +{ + va_list ap; + va_start (ap, format); + if (error == 0) + vfprintf (stderr, format, ap); + else + { + char buffer[1000]; + vsnprintf (buffer, sizeof buffer, format, ap); + errno = error; + perror (buffer); + } + va_end (ap); + fflush (NULL); + exit (EXIT_FAILURE); +} + +/* This binary is trivial, so we use a single global filter context + object that we release using `atexit'. */ + +static scmp_filter_ctx ctx; + +static void +release_context (void) +{ + seccomp_release (ctx); +} + +/* Wrapper functions and macros for libseccomp functions. We exit + immediately upon any error to avoid error checking noise. */ + +static void +set_attribute (enum scmp_filter_attr attr, uint32_t value) +{ + int status = seccomp_attr_set (ctx, attr, value); + if (status < 0) + fail (-status, "seccomp_attr_set (ctx, %u, %u)", attr, value); +} + +/* Like `seccomp_rule_add (ACTION, SYSCALL, ...)', except that you + don't have to specify the number of comparator arguments, and any + failure will exit the process. */ + +#define RULE(action, syscall, ...) \ + do \ + { \ + const struct scmp_arg_cmp arg_array[] = {__VA_ARGS__}; \ + enum { arg_cnt = sizeof arg_array / sizeof *arg_array }; \ + int status = seccomp_rule_add_array (ctx, (action), (syscall), \ + arg_cnt, arg_array); \ + if (status < 0) \ + fail (-status, "seccomp_rule_add_array (%s, %s, %d, {%s})", \ + #action, #syscall, arg_cnt, #__VA_ARGS__); \ + } \ + while (false) + +static void +export_filter (const char *file, + int (*function) (const scmp_filter_ctx, int), + const char *name) +{ + int fd = TEMP_FAILURE_RETRY ( + open (file, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_CLOEXEC, + 0644)); + if (fd < 0) + fail (errno, "open %s", file); + int status = function (ctx, fd); + if (status < 0) + fail (-status, "%s", name); + if (close (fd) != 0) + fail (errno, "close"); +} + +#define EXPORT_FILTER(file, function) \ + export_filter ((file), (function), #function) + +int +main (int argc, char **argv) +{ + if (argc != 3) + fail (0, "usage: %s out.bpf out.pfc", argv[0]); + + /* Any unhandled syscall should abort the Emacs process. */ + ctx = seccomp_init (SCMP_ACT_KILL_PROCESS); + if (ctx == NULL) + fail (0, "seccomp_init"); + atexit (release_context); + + /* We want to abort immediately if the architecture is unknown. */ + set_attribute (SCMP_FLTATR_ACT_BADARCH, SCMP_ACT_KILL_PROCESS); + set_attribute (SCMP_FLTATR_CTL_NNP, 1); + set_attribute (SCMP_FLTATR_CTL_TSYNC, 1); + set_attribute (SCMP_FLTATR_CTL_LOG, 0); + + verify (CHAR_BIT == 8); + verify (sizeof (int) == 4 && INT_MIN == INT32_MIN + && INT_MAX == INT32_MAX); + verify (sizeof (void *) == 8); + verify ((uintptr_t) NULL == 0); + + /* Allow a clean exit. */ + RULE (SCMP_ACT_ALLOW, SCMP_SYS (exit)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (exit_group)); + + /* Allow `mmap' and friends. This is necessary for dynamic loading, + reading the portable dump file, and thread creation. We don't + allow pages to be both writable and executable. */ + verify (MAP_PRIVATE != 0); + verify (MAP_SHARED != 0); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (mmap), + SCMP_A2_32 (SCMP_CMP_MASKED_EQ, + ~(PROT_NONE | PROT_READ | PROT_WRITE)), + /* Only support known flags. MAP_DENYWRITE is ignored, but + some versions of the dynamic loader still use it. Also + allow allocating thread stacks. */ + SCMP_A3_32 (SCMP_CMP_MASKED_EQ, + ~(MAP_PRIVATE | MAP_FILE | MAP_ANONYMOUS + | MAP_FIXED | MAP_DENYWRITE | MAP_STACK + | MAP_NORESERVE), + 0)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (mmap), + SCMP_A2_32 (SCMP_CMP_MASKED_EQ, + ~(PROT_NONE | PROT_READ | PROT_EXEC)), + /* Only support known flags. MAP_DENYWRITE is ignored, but + some versions of the dynamic loader still use it. */ + SCMP_A3_32 (SCMP_CMP_MASKED_EQ, + ~(MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED + | MAP_DENYWRITE), + 0)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (munmap)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (mprotect), + /* Don't allow making pages executable. */ + SCMP_A2_32 (SCMP_CMP_MASKED_EQ, + ~(PROT_NONE | PROT_READ | PROT_WRITE), 0)); + + /* Futexes are used everywhere. */ + RULE (SCMP_ACT_ALLOW, SCMP_SYS (futex), + SCMP_A1_32 (SCMP_CMP_EQ, FUTEX_WAKE_PRIVATE)); + + /* Allow basic dynamic memory management. */ + RULE (SCMP_ACT_ALLOW, SCMP_SYS (brk)); + + /* Allow some status inquiries. */ + RULE (SCMP_ACT_ALLOW, SCMP_SYS (uname)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (getuid)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (geteuid)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (getpid)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (getpgrp)); + + /* Allow operations on open file descriptors. File descriptors are + capabilities, and operating on them shouldn't cause security + issues. */ + RULE (SCMP_ACT_ALLOW, SCMP_SYS (read)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (write)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (close)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (lseek)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (dup)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (dup2)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (fstat)); + + /* Allow read operations on the filesystem. If necessary, these + should be further restricted using mount namespaces. */ + RULE (SCMP_ACT_ALLOW, SCMP_SYS (access)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (faccessat)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (stat)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (stat64)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (lstat)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (lstat64)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (fstatat64)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (newfstatat)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (readlink)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (readlinkat)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (getcwd)); + + /* Allow opening files, assuming they are only opened for + reading. */ + verify (O_WRONLY != 0); + verify (O_RDWR != 0); + verify (O_CREAT != 0); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (open), + SCMP_A1_32 (SCMP_CMP_MASKED_EQ, + ~(O_RDONLY | O_BINARY | O_CLOEXEC | O_PATH + | O_DIRECTORY), + 0)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (openat), + SCMP_A2_32 (SCMP_CMP_MASKED_EQ, + ~(O_RDONLY | O_BINARY | O_CLOEXEC | O_PATH + | O_DIRECTORY), + 0)); + + /* Allow `tcgetpgrp'. */ + RULE (SCMP_ACT_ALLOW, SCMP_SYS (ioctl), + SCMP_A0_32 (SCMP_CMP_EQ, STDIN_FILENO), + SCMP_A1_32 (SCMP_CMP_EQ, TIOCGPGRP)); + + /* Allow reading (but not setting) file flags. */ + RULE (SCMP_ACT_ALLOW, SCMP_SYS (fcntl), + SCMP_A1_32 (SCMP_CMP_EQ, F_GETFL)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (fcntl64), + SCMP_A1_32 (SCMP_CMP_EQ, F_GETFL)); + + /* Allow reading random numbers from the kernel. */ + RULE (SCMP_ACT_ALLOW, SCMP_SYS (getrandom)); + + /* Changing the umask is uncritical. */ + RULE (SCMP_ACT_ALLOW, SCMP_SYS (umask)); + + /* Allow creation of pipes. */ + RULE (SCMP_ACT_ALLOW, SCMP_SYS (pipe)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (pipe2)); + + /* Allow reading (but not changing) resource limits. */ + RULE (SCMP_ACT_ALLOW, SCMP_SYS (getrlimit)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (prlimit64), + SCMP_A0_32 (SCMP_CMP_EQ, 0) /* pid == 0 (current process) */, + SCMP_A2_64 (SCMP_CMP_EQ, 0) /* new_limit == NULL */); + + /* Block changing resource limits, but don't crash. */ + RULE (SCMP_ACT_ERRNO (EPERM), SCMP_SYS (prlimit64), + SCMP_A0_32 (SCMP_CMP_EQ, 0) /* pid == 0 (current process) */, + SCMP_A2_64 (SCMP_CMP_NE, 0) /* new_limit != NULL */); + + /* Emacs installs signal handlers, which is harmless. */ + RULE (SCMP_ACT_ALLOW, SCMP_SYS (sigaction)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (rt_sigaction)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (sigprocmask)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (rt_sigprocmask)); + + /* Allow timer support. */ + RULE (SCMP_ACT_ALLOW, SCMP_SYS (timer_create)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (timerfd_create)); + + /* Allow thread creation. See the NOTES section in the manual page + for the `clone' function. */ + RULE (SCMP_ACT_ALLOW, SCMP_SYS (clone), + SCMP_A0_64 (SCMP_CMP_MASKED_EQ, + /* Flags needed to create threads. See + create_thread in libc. */ + ~(CLONE_VM | CLONE_FS | CLONE_FILES + | CLONE_SYSVSEM | CLONE_SIGHAND | CLONE_THREAD + | CLONE_SETTLS | CLONE_PARENT_SETTID + | CLONE_CHILD_CLEARTID), + 0)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (sigaltstack)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (set_robust_list)); + + /* Allow setting the process name for new threads. */ + RULE (SCMP_ACT_ALLOW, SCMP_SYS (prctl), + SCMP_A0_32 (SCMP_CMP_EQ, PR_SET_NAME)); + + /* Allow some event handling functions used by glib. */ + RULE (SCMP_ACT_ALLOW, SCMP_SYS (eventfd)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (eventfd2)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (wait4)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (poll)); + + /* Don't allow creating sockets (network access would be extremely + dangerous), but also don't crash. */ + RULE (SCMP_ACT_ERRNO (EACCES), SCMP_SYS (socket)); + + EXPORT_FILTER (argv[1], seccomp_export_bpf); + EXPORT_FILTER (argv[2], seccomp_export_pfc); +} diff --git a/test/Makefile.in b/test/Makefile.in index ba354289e28..91a8ea141c3 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -276,6 +276,8 @@ $(test_module): $(test_module:${SO}=.c) ../src/emacs-module.h $(srcdir)/../lib/timespec.c $(srcdir)/../lib/gettime.c endif +src/emacs-tests.log: ../lib-src/seccomp-filter.c + ## Check that there is no 'automated' subdirectory, which would ## indicate an incomplete merge from an older version of Emacs where ## the tests were arranged differently. diff --git a/test/src/emacs-resources/seccomp-filter.bpf b/test/src/emacs-resources/seccomp-filter.bpf new file mode 120000 index 00000000000..b3d603d0aeb --- /dev/null +++ b/test/src/emacs-resources/seccomp-filter.bpf @@ -0,0 +1 @@ +../../../lib-src/seccomp-filter.bpf \ No newline at end of file diff --git a/test/src/emacs-tests.el b/test/src/emacs-tests.el index 7618a9c6752..89d811f8b4e 100644 --- a/test/src/emacs-tests.el +++ b/test/src/emacs-tests.el @@ -25,7 +25,9 @@ (require 'cl-lib) (require 'ert) +(require 'ert-x) (require 'rx) +(require 'subr-x) (ert-deftest emacs-tests/seccomp/absent-file () (skip-unless (string-match-p (rx bow "SECCOMP" eow) @@ -128,4 +130,51 @@ to `make-temp-file', which see." (concat "--seccomp=" filter)) 0))))) +(ert-deftest emacs-tests/seccomp/allows-stdout () + (skip-unless (string-match-p (rx bow "SECCOMP" eow) + system-configuration-features)) + (let ((emacs + (expand-file-name invocation-name invocation-directory)) + (filter (ert-resource-file "seccomp-filter.bpf")) + (process-environment nil)) + (skip-unless (file-executable-p emacs)) + (skip-unless (file-readable-p filter)) + ;; The --seccomp option is processed early, without filename + ;; handlers. Therefore remote or quoted filenames wouldn't work. + (should-not (file-remote-p filter)) + (cl-callf file-name-unquote filter) + (with-temp-buffer + (let ((status (call-process + emacs nil t nil + "--quick" "--batch" + (concat "--seccomp=" filter) + (format "--eval=%S" '(message "Hi"))))) + (ert-info ((format "Process output: %s" (buffer-string))) + (should (eql status 0))) + (should (equal (string-trim (buffer-string)) "Hi")))))) + +(ert-deftest emacs-tests/seccomp/forbids-subprocess () + (skip-unless (string-match-p (rx bow "SECCOMP" eow) + system-configuration-features)) + (let ((emacs + (expand-file-name invocation-name invocation-directory)) + (filter (ert-resource-file "seccomp-filter.bpf")) + (process-environment nil)) + (skip-unless (file-executable-p emacs)) + (skip-unless (file-readable-p filter)) + ;; The --seccomp option is processed early, without filename + ;; handlers. Therefore remote or quoted filenames wouldn't work. + (should-not (file-remote-p filter)) + (cl-callf file-name-unquote filter) + (with-temp-buffer + (let ((status + (call-process + emacs nil t nil + "--quick" "--batch" + (concat "--seccomp=" filter) + (format "--eval=%S" `(call-process ,emacs nil nil nil + "--version"))))) + (ert-info ((format "Process output: %s" (buffer-string))) + (should-not (eql status 0))))))) + ;;; emacs-tests.el ends here -- cgit v1.2.3 From c8d542fd593f06b85d4b7b712378a4f84ec4d2b3 Mon Sep 17 00:00:00 2001 From: Philipp Stephani Date: Sun, 11 Apr 2021 19:47:36 +0200 Subject: Add a variant of the Seccomp filter file that allows 'execve'. This is useful when starting Emacs with a Seccomp filter enabled, e.g. using 'bwrap'. * lib-src/seccomp-filter.c (main): Generate new Seccomp files. * lib-src/Makefile.in (all) (seccomp-filter.bpf seccomp-filter.pfc seccomp-filter-exec.bpf seccomp-filter-exec.pfc): Generate new Seccomp files. * .gitignore: Ignore new Seccomp files. * test/src/emacs-tests.el (emacs-tests/bwrap/allows-stdout): New unit test. --- .gitignore | 2 ++ lib-src/Makefile.in | 7 +++-- lib-src/seccomp-filter.c | 39 +++++++++++++++++++++--- test/src/emacs-resources/seccomp-filter-exec.bpf | 1 + test/src/emacs-tests.el | 33 ++++++++++++++++++++ 5 files changed, 75 insertions(+), 7 deletions(-) create mode 120000 test/src/emacs-resources/seccomp-filter-exec.bpf (limited to '.gitignore') diff --git a/.gitignore b/.gitignore index ecf768dc4d6..a1e3cb92f87 100644 --- a/.gitignore +++ b/.gitignore @@ -306,3 +306,5 @@ src/gdb.ini # Seccomp filter files. lib-src/seccomp-filter.bpf lib-src/seccomp-filter.pfc +lib-src/seccomp-filter-exec.bpf +lib-src/seccomp-filter-exec.pfc diff --git a/lib-src/Makefile.in b/lib-src/Makefile.in index 35cfa56d8be..091f4fb0199 100644 --- a/lib-src/Makefile.in +++ b/lib-src/Makefile.in @@ -240,7 +240,7 @@ config_h = ../src/config.h $(srcdir)/../src/conf_post.h all: ${EXE_FILES} ${SCRIPTS} ifeq ($(SECCOMP_FILTER),1) -all: seccomp-filter.bpf +all: seccomp-filter.bpf seccomp-filter-exec.bpf endif .PHONY: all need-blessmail maybe-blessmail @@ -430,9 +430,10 @@ seccomp-filter$(EXEEXT): $(srcdir)/seccomp-filter.c $(config_h) $(AM_V_CCLD)$(CC) $(ALL_CFLAGS) $(LIBSECCOMP_CFLAGS) $< \ $(LIBSECCOMP_LIBS) -o $@ -seccomp-filter.bpf seccomp-filter.pfc: seccomp-filter$(EXEEXT) +seccomp-filter.bpf seccomp-filter.pfc seccomp-filter-exec.bpf seccomp-filter-exec.pfc: seccomp-filter$(EXEEXT) $(AM_V_GEN)./seccomp-filter$(EXEEXT) \ - seccomp-filter.bpf seccomp-filter.pfc + seccomp-filter.bpf seccomp-filter.pfc \ + seccomp-filter-exec.bpf seccomp-filter-exec.pfc endif ## Makefile ends here. diff --git a/lib-src/seccomp-filter.c b/lib-src/seccomp-filter.c index a5f2e0adbca..ed362bc18d9 100644 --- a/lib-src/seccomp-filter.c +++ b/lib-src/seccomp-filter.c @@ -26,10 +26,12 @@ only a Linux kernel supporting the Secure Computing extension. Usage: - seccomp-filter out.bpf out.pfc + seccomp-filter out.bpf out.pfc out-exec.bpf out-exec.pfc This writes the raw `struct sock_filter' array to out.bpf and a -human-readable representation to out.pfc. */ +human-readable representation to out.pfc. Additionally, it writes +variants of those files that can be used to sandbox Emacs before +'execve' to out-exec.bpf and out-exec.pfc. */ #include "config.h" @@ -42,6 +44,7 @@ human-readable representation to out.pfc. */ #include #include +#include #include #include #include @@ -139,8 +142,9 @@ export_filter (const char *file, int main (int argc, char **argv) { - if (argc != 3) - fail (0, "usage: %s out.bpf out.pfc", argv[0]); + if (argc != 5) + fail (0, "usage: %s out.bpf out.pfc out-exec.bpf out-exec.pfc", + argv[0]); /* Any unhandled syscall should abort the Emacs process. */ ctx = seccomp_init (SCMP_ACT_KILL_PROCESS); @@ -156,6 +160,8 @@ main (int argc, char **argv) verify (CHAR_BIT == 8); verify (sizeof (int) == 4 && INT_MIN == INT32_MIN && INT_MAX == INT32_MAX); + verify (sizeof (long) == 8 && LONG_MIN == INT64_MIN + && LONG_MAX == INT64_MAX); verify (sizeof (void *) == 8); verify ((uintptr_t) NULL == 0); @@ -327,4 +333,29 @@ main (int argc, char **argv) EXPORT_FILTER (argv[1], seccomp_export_bpf); EXPORT_FILTER (argv[2], seccomp_export_pfc); + + /* When applying a Seccomp filter before executing the Emacs binary + (e.g. using the `bwrap' program), we need to allow further system + calls. Firstly, the wrapper binary will need to `execve' the + Emacs binary. Furthermore, the C library requires some system + calls at startup time to set up thread-local storage. */ + RULE (SCMP_ACT_ALLOW, SCMP_SYS (execve)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (set_tid_address)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (arch_prctl), + SCMP_A0_32 (SCMP_CMP_EQ, ARCH_SET_FS)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (statfs)); + + /* We want to allow starting the Emacs binary itself with the + --seccomp flag, so we need to allow the `prctl' and `seccomp' + system calls. */ + RULE (SCMP_ACT_ALLOW, SCMP_SYS (prctl), + SCMP_A0_32 (SCMP_CMP_EQ, PR_SET_NO_NEW_PRIVS), + SCMP_A1_64 (SCMP_CMP_EQ, 1), SCMP_A2_64 (SCMP_CMP_EQ, 0), + SCMP_A3_64 (SCMP_CMP_EQ, 0), SCMP_A4_64 (SCMP_CMP_EQ, 0)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (seccomp), + SCMP_A0_32 (SCMP_CMP_EQ, SECCOMP_SET_MODE_FILTER), + SCMP_A1_32 (SCMP_CMP_EQ, SECCOMP_FILTER_FLAG_TSYNC)); + + EXPORT_FILTER (argv[3], seccomp_export_bpf); + EXPORT_FILTER (argv[4], seccomp_export_pfc); } diff --git a/test/src/emacs-resources/seccomp-filter-exec.bpf b/test/src/emacs-resources/seccomp-filter-exec.bpf new file mode 120000 index 00000000000..5b0e9978221 --- /dev/null +++ b/test/src/emacs-resources/seccomp-filter-exec.bpf @@ -0,0 +1 @@ +../../../lib-src/seccomp-filter-exec.bpf \ No newline at end of file diff --git a/test/src/emacs-tests.el b/test/src/emacs-tests.el index 89d811f8b4e..09f9a248efb 100644 --- a/test/src/emacs-tests.el +++ b/test/src/emacs-tests.el @@ -177,4 +177,37 @@ to `make-temp-file', which see." (ert-info ((format "Process output: %s" (buffer-string))) (should-not (eql status 0))))))) +(ert-deftest emacs-tests/bwrap/allows-stdout () + (let ((bash (executable-find "bash")) + (bwrap (executable-find "bwrap")) + (emacs + (expand-file-name invocation-name invocation-directory)) + (filter (ert-resource-file "seccomp-filter-exec.bpf")) + (process-environment nil)) + (skip-unless bash) + (skip-unless bwrap) + (skip-unless (file-executable-p emacs)) + (skip-unless (file-readable-p filter)) + (should-not (file-remote-p bwrap)) + (should-not (file-remote-p emacs)) + (should-not (file-remote-p filter)) + (with-temp-buffer + (let* ((command + (concat + (mapconcat #'shell-quote-argument + `(,(file-name-unquote bwrap) + "--ro-bind" "/" "/" + "--seccomp" "20" + "--" + ,(file-name-unquote emacs) + "--quick" "--batch" + ,(format "--eval=%S" '(message "Hi"))) + " ") + " 20< " + (shell-quote-argument (file-name-unquote filter)))) + (status (call-process bash nil t nil "-c" command))) + (ert-info ((format "Process output: %s" (buffer-string))) + (should (eql status 0))) + (should (equal (string-trim (buffer-string)) "Hi")))))) + ;;; emacs-tests.el ends here -- cgit v1.2.3 From 214dfbfea0cc7d64704aa4a258da542435c44cbb Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Mon, 12 Apr 2021 21:55:50 -0400 Subject: Don't version-control generated file `grammat-wy.el` This file is needed for CEDET's bootstrap, tho, so we now keep a copy of it under version control in `gram-wy-boot.el`, very much like we do with the `ldefs-boot.el` copy of `loaddefs.el`. * lisp/cedet/semantic/grm-wy-boot.el: Rename from `lisp/cedet/semantic/grammar-wy.el`. * lisp/cedet/semantic/grammar.el: Load `grm-wy-boot.el` if `grammar-wy.el` hasn't been generated yet. * admin/update_autogen: Also refresh `grm-wy-boot.el`. * admin/grammars/Makefile.in (WISENT): Add `grammar-wy.el` to the generated files. * .gitignore: Add `grammar-wy.el`. --- .gitignore | 1 + admin/grammars/Makefile.in | 13 +- admin/update_autogen | 12 +- lisp/cedet/semantic/grammar-wy.el | 503 ------------------------------------- lisp/cedet/semantic/grammar.el | 7 +- lisp/cedet/semantic/grm-wy-boot.el | 503 +++++++++++++++++++++++++++++++++++++ lisp/emacs-lisp/eieio-base.el | 3 +- 7 files changed, 525 insertions(+), 517 deletions(-) delete mode 100644 lisp/cedet/semantic/grammar-wy.el create mode 100644 lisp/cedet/semantic/grm-wy-boot.el (limited to '.gitignore') diff --git a/.gitignore b/.gitignore index a1e3cb92f87..c262f39126d 100644 --- a/.gitignore +++ b/.gitignore @@ -88,6 +88,7 @@ lisp/cedet/semantic/wisent/javat-wy.el lisp/cedet/semantic/wisent/js-wy.el lisp/cedet/semantic/wisent/python-wy.el lisp/cedet/srecode/srt-wy.el +lisp/cedet/semantic/grammar-wy.el lisp/eshell/esh-groups.el lisp/finder-inf.el lisp/leim/ja-dic/ diff --git a/admin/grammars/Makefile.in b/admin/grammars/Makefile.in index 35ce55461f3..4172411e034 100644 --- a/admin/grammars/Makefile.in +++ b/admin/grammars/Makefile.in @@ -51,14 +51,11 @@ BOVINE = \ ${bovinedir}/make-by.el \ ${bovinedir}/scm-by.el -## FIXME Should include this one too: -## ${cedetdir}/semantic/grammar-wy.el -## but semantic/grammar.el (which is what we use to generate grammar-wy.el) -## requires it! https://debbugs.gnu.org/16008 -WISENT = \ - ${wisentdir}/javat-wy.el \ - ${wisentdir}/js-wy.el \ - ${wisentdir}/python-wy.el \ +WISENT = \ + ${cedetdir}/semantic/grammar-wy.el \ + ${wisentdir}/javat-wy.el \ + ${wisentdir}/js-wy.el \ + ${wisentdir}/python-wy.el \ ${cedetdir}/srecode/srt-wy.el ALL = ${BOVINE} ${WISENT} diff --git a/admin/update_autogen b/admin/update_autogen index 35c391da19e..11c4313ae37 100755 --- a/admin/update_autogen +++ b/admin/update_autogen @@ -317,7 +317,7 @@ EOF echo "Finding loaddef targets..." find lisp -name '*.el' -exec grep '^;.*generated-autoload-file:' {} + | \ - sed -e '/loaddefs\|esh-groups/d' -e 's|/[^/]*: "|/|' -e 's/"//g' \ + sed -e '/loaddefs\|esh-groups/d' -e 's|/[^/]*: "|/|' -e 's/"//g' \ >| $tempfile || die "Error finding targets" genfiles= @@ -363,17 +363,23 @@ make -C lisp "$@" autoloads EMACS=../src/bootstrap-emacs || die "make src error" ## Ignore comment differences. -[ ! "$lboot_flag" ] || \ +[ ! "$lboot_flag" ] || \ diff -q -I '^;' $ldefs_in $ldefs_out || \ cp $ldefs_in $ldefs_out || die "cp ldefs_boot error" +# Refresh the prebuilt grammar-wy.el +grammar_in=lisp/cedet/semantic/grammar-wy.el +grammar_out=lisp/cedet/semantic/grm-wy-boot.el +make -C admin/grammars/ ../../$grammar_in +cp $grammar_in $grammar_out || die "cp grm_wy_boot error" + echo "Checking status of loaddef files..." ## It probably would be fine to just check+commit lisp/, since ## making autoloads should not effect any other files. But better ## safe than sorry. -modified=$(status $genfiles $ldefs_out) || die +modified=$(status $genfiles $ldefs_out $grammar_out) || die commit "loaddefs" $modified || die "commit error" diff --git a/lisp/cedet/semantic/grammar-wy.el b/lisp/cedet/semantic/grammar-wy.el deleted file mode 100644 index b3014034374..00000000000 --- a/lisp/cedet/semantic/grammar-wy.el +++ /dev/null @@ -1,503 +0,0 @@ -;;; semantic/grammar-wy.el --- Generated parser support file -*- lexical-binding:t -*- - -;; Copyright (C) 2002-2021 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 . - -;;; Commentary: -;; -;; This file was generated from admin/grammars/grammar.wy. - -;;; Code: - -(require 'semantic/lex) -(require 'semantic/wisent) - -;;; Prologue -;; -(defvar semantic-grammar-lex-c-char-re) - -;; Current parsed nonterminal name. -(defvar semantic-grammar-wy--nterm nil) -;; Index of rule in a nonterminal clause. -(defvar semantic-grammar-wy--rindx nil) - -;;; Declarations -;; -(eval-and-compile (defconst semantic-grammar-wy--expected-conflicts - nil - "The number of expected shift/reduce conflicts in this grammar.")) - -(defconst semantic-grammar-wy--keyword-table - (semantic-lex-make-keyword-table - '(("%default-prec" . DEFAULT-PREC) - ("%no-default-prec" . NO-DEFAULT-PREC) - ("%keyword" . KEYWORD) - ("%languagemode" . LANGUAGEMODE) - ("%left" . LEFT) - ("%nonassoc" . NONASSOC) - ("%package" . PACKAGE) - ("%expectedconflicts" . EXPECTEDCONFLICTS) - ("%provide" . PROVIDE) - ("%prec" . PREC) - ("%put" . PUT) - ("%quotemode" . QUOTEMODE) - ("%right" . RIGHT) - ("%scopestart" . SCOPESTART) - ("%start" . START) - ("%token" . TOKEN) - ("%type" . TYPE) - ("%use-macros" . USE-MACROS)) - 'nil) - "Table of language keywords.") - -(defconst semantic-grammar-wy--token-table - (semantic-lex-make-type-table - '(("punctuation" - (GT . ">") - (LT . "<") - (OR . "|") - (SEMI . ";") - (COLON . ":")) - ("close-paren" - (RBRACE . "}") - (RPAREN . ")")) - ("open-paren" - (LBRACE . "{") - (LPAREN . "(")) - ("block" - (BRACE_BLOCK . "(LBRACE RBRACE)") - (PAREN_BLOCK . "(LPAREN RPAREN)")) - ("code" - (EPILOGUE . "%%...EOF") - (PROLOGUE . "%{...%}")) - ("sexp" - (SEXP)) - ("qlist" - (PREFIXED_LIST)) - ("char" - (CHARACTER)) - ("symbol" - (PERCENT_PERCENT . "\\`%%\\'") - (SYMBOL)) - ("string" - (STRING))) - '(("punctuation" :declared t) - ("block" :declared t) - ("sexp" matchdatatype sexp) - ("sexp" syntax "\\=") - ("sexp" :declared t) - ("qlist" matchdatatype sexp) - ("qlist" syntax "\\s'\\s-*(") - ("qlist" :declared t) - ("char" syntax semantic-grammar-lex-c-char-re) - ("char" :declared t) - ("symbol" syntax ":?\\(\\sw\\|\\s_\\)+") - ("symbol" :declared t) - ("string" :declared t) - ("keyword" :declared t))) - "Table of lexical tokens.") - -(defconst semantic-grammar-wy--parse-table - (wisent-compiled-grammar - ((DEFAULT-PREC NO-DEFAULT-PREC KEYWORD LANGUAGEMODE LEFT NONASSOC PACKAGE EXPECTEDCONFLICTS PROVIDE PREC PUT QUOTEMODE RIGHT SCOPESTART START TOKEN TYPE USE-MACROS STRING SYMBOL PERCENT_PERCENT CHARACTER PREFIXED_LIST SEXP PROLOGUE EPILOGUE PAREN_BLOCK BRACE_BLOCK LPAREN RPAREN LBRACE RBRACE COLON SEMI OR LT GT) - nil - (grammar - ((prologue)) - ((epilogue)) - ((declaration)) - ((nonterminal)) - ((PERCENT_PERCENT))) - (prologue - ((PROLOGUE) - (wisent-raw-tag - (semantic-tag-new-code "prologue" nil)))) - (epilogue - ((EPILOGUE) - (wisent-raw-tag - (semantic-tag-new-code "epilogue" nil)))) - (declaration - ((decl) - (eval $1 t))) - (decl - ((default_prec_decl)) - ((no_default_prec_decl)) - ((languagemode_decl)) - ((package_decl)) - ((expectedconflicts_decl)) - ((provide_decl)) - ((precedence_decl)) - ((put_decl)) - ((quotemode_decl)) - ((scopestart_decl)) - ((start_decl)) - ((keyword_decl)) - ((token_decl)) - ((type_decl)) - ((use_macros_decl))) - (default_prec_decl - ((DEFAULT-PREC) - `(wisent-raw-tag - (semantic-tag "default-prec" 'assoc :value - '("t"))))) - (no_default_prec_decl - ((NO-DEFAULT-PREC) - `(wisent-raw-tag - (semantic-tag "default-prec" 'assoc :value - '("nil"))))) - (languagemode_decl - ((LANGUAGEMODE symbols) - `(wisent-raw-tag - (semantic-tag ',(car $2) - 'languagemode :rest ',(cdr $2))))) - (package_decl - ((PACKAGE SYMBOL) - `(wisent-raw-tag - (semantic-tag-new-package ',$2 nil)))) - (expectedconflicts_decl - ((EXPECTEDCONFLICTS symbols) - `(wisent-raw-tag - (semantic-tag ',(car $2) - 'expectedconflicts :rest ',(cdr $2))))) - (provide_decl - ((PROVIDE SYMBOL) - `(wisent-raw-tag - (semantic-tag ',$2 'provide)))) - (precedence_decl - ((associativity token_type_opt items) - `(wisent-raw-tag - (semantic-tag ',$1 'assoc :type ',$2 :value ',$3)))) - (associativity - ((LEFT) - (progn "left")) - ((RIGHT) - (progn "right")) - ((NONASSOC) - (progn "nonassoc"))) - (put_decl - ((PUT put_name put_value) - `(wisent-raw-tag - (semantic-tag ',$2 'put :value ',(list $3)))) - ((PUT put_name put_value_list) - `(wisent-raw-tag - (semantic-tag ',$2 'put :value ',$3))) - ((PUT put_name_list put_value) - `(wisent-raw-tag - (semantic-tag ',(car $2) - 'put :rest ',(cdr $2) - :value ',(list $3)))) - ((PUT put_name_list put_value_list) - `(wisent-raw-tag - (semantic-tag ',(car $2) - 'put :rest ',(cdr $2) - :value ',$3)))) - (put_name_list - ((BRACE_BLOCK) - (mapcar #'semantic-tag-name - (semantic-parse-region - (car $region1) - (cdr $region1) - 'put_names 1)))) - (put_names - ((LBRACE) - nil) - ((RBRACE) - nil) - ((put_name) - (wisent-raw-tag - (semantic-tag $1 'put-name)))) - (put_name - ((SYMBOL)) - ((token_type))) - (put_value_list - ((BRACE_BLOCK) - (mapcar #'semantic-tag-code-detail - (semantic-parse-region - (car $region1) - (cdr $region1) - 'put_values 1)))) - (put_values - ((LBRACE) - nil) - ((RBRACE) - nil) - ((put_value) - (wisent-raw-tag - (semantic-tag-new-code "put-value" $1)))) - (put_value - ((SYMBOL any_value) - (cons $1 $2))) - (scopestart_decl - ((SCOPESTART SYMBOL) - `(wisent-raw-tag - (semantic-tag ',$2 'scopestart)))) - (quotemode_decl - ((QUOTEMODE SYMBOL) - `(wisent-raw-tag - (semantic-tag ',$2 'quotemode)))) - (start_decl - ((START symbols) - `(wisent-raw-tag - (semantic-tag ',(car $2) - 'start :rest ',(cdr $2))))) - (keyword_decl - ((KEYWORD SYMBOL string_value) - `(wisent-raw-tag - (semantic-tag ',$2 'keyword :value ',$3)))) - (token_decl - ((TOKEN token_type_opt SYMBOL string_value) - `(wisent-raw-tag - (semantic-tag ',$3 ',(if $2 'token 'keyword) - :type ',$2 :value ',$4))) - ((TOKEN token_type_opt symbols) - `(wisent-raw-tag - (semantic-tag ',(car $3) - 'token :type ',$2 :rest ',(cdr $3))))) - (token_type_opt - (nil) - ((token_type))) - (token_type - ((LT SYMBOL GT) - (progn $2))) - (type_decl - ((TYPE token_type plist_opt) - `(wisent-raw-tag - (semantic-tag ',$2 'type :value ',$3)))) - (plist_opt - (nil) - ((plist))) - (plist - ((plist put_value) - (append - (list $2) - $1)) - ((put_value) - (list $1))) - (use_name_list - ((BRACE_BLOCK) - (mapcar #'semantic-tag-name - (semantic-parse-region - (car $region1) - (cdr $region1) - 'use_names 1)))) - (use_names - ((LBRACE) - nil) - ((RBRACE) - nil) - ((SYMBOL) - (wisent-raw-tag - (semantic-tag $1 'use-name)))) - (use_macros_decl - ((USE-MACROS SYMBOL use_name_list) - `(wisent-raw-tag - (semantic-tag "macro" 'macro :type ',$2 :value ',$3)))) - (string_value - ((STRING) - (read $1))) - (any_value - ((SYMBOL)) - ((STRING)) - ((PAREN_BLOCK)) - ((PREFIXED_LIST)) - ((SEXP))) - (symbols - ((lifo_symbols) - (nreverse $1))) - (lifo_symbols - ((lifo_symbols SYMBOL) - (cons $2 $1)) - ((SYMBOL) - (list $1))) - (nonterminal - ((SYMBOL - (setq semantic-grammar-wy--nterm $1 semantic-grammar-wy--rindx 0) - COLON rules SEMI) - (wisent-raw-tag - (semantic-tag $1 'nonterminal :children $4)))) - (rules - ((lifo_rules) - (apply #'nconc - (nreverse $1)))) - (lifo_rules - ((lifo_rules OR rule) - (cons $3 $1)) - ((rule) - (list $1))) - (rule - ((rhs) - (let* - ((nterm semantic-grammar-wy--nterm) - (rindx semantic-grammar-wy--rindx) - (rhs $1) - comps prec action elt) - (setq semantic-grammar-wy--rindx - (1+ semantic-grammar-wy--rindx)) - (while rhs - (setq elt - (car rhs) - rhs - (cdr rhs)) - (cond - ((vectorp elt) - (if prec - (error "Duplicate %%prec in `%s:%d' rule" nterm rindx)) - (setq prec - (aref elt 0))) - ((consp elt) - (if - (or action comps) - (setq comps - (cons elt comps) - semantic-grammar-wy--rindx - (1+ semantic-grammar-wy--rindx)) - (setq action - (car elt)))) - (t - (setq comps - (cons elt comps))))) - (wisent-cook-tag - (wisent-raw-tag - (semantic-tag - (format "%s:%d" nterm rindx) - 'rule :type - (if comps "group" "empty") - :value comps :prec prec :expr action)))))) - (rhs - (nil) - ((rhs item) - (cons $2 $1)) - ((rhs action) - (cons - (list $2) - $1)) - ((rhs PREC item) - (cons - (vector $3) - $1))) - (action - ((PAREN_BLOCK)) - ((PREFIXED_LIST)) - ((BRACE_BLOCK) - (format "(progn\n%s)" - (let - ((s $1)) - (if - (string-match "^{[ \n ]*" s) - (setq s - (substring s - (match-end 0)))) - (if - (string-match "[ \n ]*}$" s) - (setq s - (substring s 0 - (match-beginning 0)))) - s)))) - (items - ((lifo_items) - (nreverse $1))) - (lifo_items - ((lifo_items item) - (cons $2 $1)) - ((item) - (list $1))) - (item - ((SYMBOL)) - ((CHARACTER)))) - (grammar prologue epilogue declaration nonterminal rule put_names put_values use_names)) - "Parser table.") - -(defun semantic-grammar-wy--install-parser () - "Setup the Semantic Parser." - (semantic-install-function-overrides - '((semantic-parse-stream . wisent-parse-stream))) - (setq semantic-parser-name "LALR" - semantic--parse-table semantic-grammar-wy--parse-table - semantic-debug-parser-source "grammar.wy" - semantic-flex-keywords-obarray semantic-grammar-wy--keyword-table - semantic-lex-types-obarray semantic-grammar-wy--token-table) - ;; Collect unmatched syntax lexical tokens - (add-hook 'wisent-discarding-token-functions - #'wisent-collect-unmatched-syntax nil t)) - - -;;; Analyzers -;; -(define-lex-regex-type-analyzer semantic-grammar-wy---regexp-analyzer - "regexp analyzer for tokens." - ":?\\(\\sw\\|\\s_\\)+" - '((PERCENT_PERCENT . "\\`%%\\'")) - 'SYMBOL) - -(define-lex-keyword-type-analyzer semantic-grammar-wy---keyword-analyzer - "keyword analyzer for tokens." - "\\(\\sw\\|\\s_\\)+") - -(define-lex-regex-type-analyzer semantic-grammar-wy---regexp-analyzer - "regexp analyzer for tokens." - semantic-grammar-lex-c-char-re - nil - 'CHARACTER) - -(define-lex-sexp-type-analyzer semantic-grammar-wy---sexp-analyzer - "sexp analyzer for tokens." - "\\s'\\s-*(" - 'PREFIXED_LIST) - -(define-lex-block-type-analyzer semantic-grammar-wy---block-analyzer - "block analyzer for tokens." - "\\s(\\|\\s)" - '((("(" LPAREN PAREN_BLOCK) - ("{" LBRACE BRACE_BLOCK)) - (")" RPAREN) - ("}" RBRACE)) - ) - -(define-lex-string-type-analyzer semantic-grammar-wy---string-analyzer - "string analyzer for tokens." - "\\(\\s.\\|\\s$\\|\\s'\\)+" - '((GT . ">") - (LT . "<") - (OR . "|") - (SEMI . ";") - (COLON . ":")) - 'punctuation) - -(define-lex-sexp-type-analyzer semantic-grammar-wy---sexp-analyzer - "sexp analyzer for tokens." - "\\s\"" - 'STRING) - -(define-lex-sexp-type-analyzer semantic-grammar-wy---sexp-analyzer - "sexp analyzer for tokens." - "\\=" - 'SEXP) - - -;;; Epilogue -;; - - - - -(provide 'semantic/grammar-wy) - -;; Local Variables: -;; version-control: never -;; no-update-autoloads: t -;; End: - -;;; semantic/grammar-wy.el ends here diff --git a/lisp/cedet/semantic/grammar.el b/lisp/cedet/semantic/grammar.el index dba289fdd75..4c3bb6c238b 100644 --- a/lisp/cedet/semantic/grammar.el +++ b/lisp/cedet/semantic/grammar.el @@ -31,7 +31,12 @@ (require 'semantic/format) ;; FIXME this is a generated file, but we need to load this file to ;; generate it! -(require 'semantic/grammar-wy) +;; We need `semantic/grammar-wy.el' but we're also needed to generate +;; that file from `grammar.wy', so to break the dependency, we keep +;; a bootstrap copy of `grammar-wy.el' in `grm-wy-boot.el'. See bug#16008. +(eval-and-compile + (unless (require 'semantic/grammar-wy nil t) + (load "semantic/grm-wy-boot"))) (require 'semantic/idle) (require 'help-fns) (require 'semantic/analyze) diff --git a/lisp/cedet/semantic/grm-wy-boot.el b/lisp/cedet/semantic/grm-wy-boot.el new file mode 100644 index 00000000000..b3014034374 --- /dev/null +++ b/lisp/cedet/semantic/grm-wy-boot.el @@ -0,0 +1,503 @@ +;;; semantic/grammar-wy.el --- Generated parser support file -*- lexical-binding:t -*- + +;; Copyright (C) 2002-2021 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 . + +;;; Commentary: +;; +;; This file was generated from admin/grammars/grammar.wy. + +;;; Code: + +(require 'semantic/lex) +(require 'semantic/wisent) + +;;; Prologue +;; +(defvar semantic-grammar-lex-c-char-re) + +;; Current parsed nonterminal name. +(defvar semantic-grammar-wy--nterm nil) +;; Index of rule in a nonterminal clause. +(defvar semantic-grammar-wy--rindx nil) + +;;; Declarations +;; +(eval-and-compile (defconst semantic-grammar-wy--expected-conflicts + nil + "The number of expected shift/reduce conflicts in this grammar.")) + +(defconst semantic-grammar-wy--keyword-table + (semantic-lex-make-keyword-table + '(("%default-prec" . DEFAULT-PREC) + ("%no-default-prec" . NO-DEFAULT-PREC) + ("%keyword" . KEYWORD) + ("%languagemode" . LANGUAGEMODE) + ("%left" . LEFT) + ("%nonassoc" . NONASSOC) + ("%package" . PACKAGE) + ("%expectedconflicts" . EXPECTEDCONFLICTS) + ("%provide" . PROVIDE) + ("%prec" . PREC) + ("%put" . PUT) + ("%quotemode" . QUOTEMODE) + ("%right" . RIGHT) + ("%scopestart" . SCOPESTART) + ("%start" . START) + ("%token" . TOKEN) + ("%type" . TYPE) + ("%use-macros" . USE-MACROS)) + 'nil) + "Table of language keywords.") + +(defconst semantic-grammar-wy--token-table + (semantic-lex-make-type-table + '(("punctuation" + (GT . ">") + (LT . "<") + (OR . "|") + (SEMI . ";") + (COLON . ":")) + ("close-paren" + (RBRACE . "}") + (RPAREN . ")")) + ("open-paren" + (LBRACE . "{") + (LPAREN . "(")) + ("block" + (BRACE_BLOCK . "(LBRACE RBRACE)") + (PAREN_BLOCK . "(LPAREN RPAREN)")) + ("code" + (EPILOGUE . "%%...EOF") + (PROLOGUE . "%{...%}")) + ("sexp" + (SEXP)) + ("qlist" + (PREFIXED_LIST)) + ("char" + (CHARACTER)) + ("symbol" + (PERCENT_PERCENT . "\\`%%\\'") + (SYMBOL)) + ("string" + (STRING))) + '(("punctuation" :declared t) + ("block" :declared t) + ("sexp" matchdatatype sexp) + ("sexp" syntax "\\=") + ("sexp" :declared t) + ("qlist" matchdatatype sexp) + ("qlist" syntax "\\s'\\s-*(") + ("qlist" :declared t) + ("char" syntax semantic-grammar-lex-c-char-re) + ("char" :declared t) + ("symbol" syntax ":?\\(\\sw\\|\\s_\\)+") + ("symbol" :declared t) + ("string" :declared t) + ("keyword" :declared t))) + "Table of lexical tokens.") + +(defconst semantic-grammar-wy--parse-table + (wisent-compiled-grammar + ((DEFAULT-PREC NO-DEFAULT-PREC KEYWORD LANGUAGEMODE LEFT NONASSOC PACKAGE EXPECTEDCONFLICTS PROVIDE PREC PUT QUOTEMODE RIGHT SCOPESTART START TOKEN TYPE USE-MACROS STRING SYMBOL PERCENT_PERCENT CHARACTER PREFIXED_LIST SEXP PROLOGUE EPILOGUE PAREN_BLOCK BRACE_BLOCK LPAREN RPAREN LBRACE RBRACE COLON SEMI OR LT GT) + nil + (grammar + ((prologue)) + ((epilogue)) + ((declaration)) + ((nonterminal)) + ((PERCENT_PERCENT))) + (prologue + ((PROLOGUE) + (wisent-raw-tag + (semantic-tag-new-code "prologue" nil)))) + (epilogue + ((EPILOGUE) + (wisent-raw-tag + (semantic-tag-new-code "epilogue" nil)))) + (declaration + ((decl) + (eval $1 t))) + (decl + ((default_prec_decl)) + ((no_default_prec_decl)) + ((languagemode_decl)) + ((package_decl)) + ((expectedconflicts_decl)) + ((provide_decl)) + ((precedence_decl)) + ((put_decl)) + ((quotemode_decl)) + ((scopestart_decl)) + ((start_decl)) + ((keyword_decl)) + ((token_decl)) + ((type_decl)) + ((use_macros_decl))) + (default_prec_decl + ((DEFAULT-PREC) + `(wisent-raw-tag + (semantic-tag "default-prec" 'assoc :value + '("t"))))) + (no_default_prec_decl + ((NO-DEFAULT-PREC) + `(wisent-raw-tag + (semantic-tag "default-prec" 'assoc :value + '("nil"))))) + (languagemode_decl + ((LANGUAGEMODE symbols) + `(wisent-raw-tag + (semantic-tag ',(car $2) + 'languagemode :rest ',(cdr $2))))) + (package_decl + ((PACKAGE SYMBOL) + `(wisent-raw-tag + (semantic-tag-new-package ',$2 nil)))) + (expectedconflicts_decl + ((EXPECTEDCONFLICTS symbols) + `(wisent-raw-tag + (semantic-tag ',(car $2) + 'expectedconflicts :rest ',(cdr $2))))) + (provide_decl + ((PROVIDE SYMBOL) + `(wisent-raw-tag + (semantic-tag ',$2 'provide)))) + (precedence_decl + ((associativity token_type_opt items) + `(wisent-raw-tag + (semantic-tag ',$1 'assoc :type ',$2 :value ',$3)))) + (associativity + ((LEFT) + (progn "left")) + ((RIGHT) + (progn "right")) + ((NONASSOC) + (progn "nonassoc"))) + (put_decl + ((PUT put_name put_value) + `(wisent-raw-tag + (semantic-tag ',$2 'put :value ',(list $3)))) + ((PUT put_name put_value_list) + `(wisent-raw-tag + (semantic-tag ',$2 'put :value ',$3))) + ((PUT put_name_list put_value) + `(wisent-raw-tag + (semantic-tag ',(car $2) + 'put :rest ',(cdr $2) + :value ',(list $3)))) + ((PUT put_name_list put_value_list) + `(wisent-raw-tag + (semantic-tag ',(car $2) + 'put :rest ',(cdr $2) + :value ',$3)))) + (put_name_list + ((BRACE_BLOCK) + (mapcar #'semantic-tag-name + (semantic-parse-region + (car $region1) + (cdr $region1) + 'put_names 1)))) + (put_names + ((LBRACE) + nil) + ((RBRACE) + nil) + ((put_name) + (wisent-raw-tag + (semantic-tag $1 'put-name)))) + (put_name + ((SYMBOL)) + ((token_type))) + (put_value_list + ((BRACE_BLOCK) + (mapcar #'semantic-tag-code-detail + (semantic-parse-region + (car $region1) + (cdr $region1) + 'put_values 1)))) + (put_values + ((LBRACE) + nil) + ((RBRACE) + nil) + ((put_value) + (wisent-raw-tag + (semantic-tag-new-code "put-value" $1)))) + (put_value + ((SYMBOL any_value) + (cons $1 $2))) + (scopestart_decl + ((SCOPESTART SYMBOL) + `(wisent-raw-tag + (semantic-tag ',$2 'scopestart)))) + (quotemode_decl + ((QUOTEMODE SYMBOL) + `(wisent-raw-tag + (semantic-tag ',$2 'quotemode)))) + (start_decl + ((START symbols) + `(wisent-raw-tag + (semantic-tag ',(car $2) + 'start :rest ',(cdr $2))))) + (keyword_decl + ((KEYWORD SYMBOL string_value) + `(wisent-raw-tag + (semantic-tag ',$2 'keyword :value ',$3)))) + (token_decl + ((TOKEN token_type_opt SYMBOL string_value) + `(wisent-raw-tag + (semantic-tag ',$3 ',(if $2 'token 'keyword) + :type ',$2 :value ',$4))) + ((TOKEN token_type_opt symbols) + `(wisent-raw-tag + (semantic-tag ',(car $3) + 'token :type ',$2 :rest ',(cdr $3))))) + (token_type_opt + (nil) + ((token_type))) + (token_type + ((LT SYMBOL GT) + (progn $2))) + (type_decl + ((TYPE token_type plist_opt) + `(wisent-raw-tag + (semantic-tag ',$2 'type :value ',$3)))) + (plist_opt + (nil) + ((plist))) + (plist + ((plist put_value) + (append + (list $2) + $1)) + ((put_value) + (list $1))) + (use_name_list + ((BRACE_BLOCK) + (mapcar #'semantic-tag-name + (semantic-parse-region + (car $region1) + (cdr $region1) + 'use_names 1)))) + (use_names + ((LBRACE) + nil) + ((RBRACE) + nil) + ((SYMBOL) + (wisent-raw-tag + (semantic-tag $1 'use-name)))) + (use_macros_decl + ((USE-MACROS SYMBOL use_name_list) + `(wisent-raw-tag + (semantic-tag "macro" 'macro :type ',$2 :value ',$3)))) + (string_value + ((STRING) + (read $1))) + (any_value + ((SYMBOL)) + ((STRING)) + ((PAREN_BLOCK)) + ((PREFIXED_LIST)) + ((SEXP))) + (symbols + ((lifo_symbols) + (nreverse $1))) + (lifo_symbols + ((lifo_symbols SYMBOL) + (cons $2 $1)) + ((SYMBOL) + (list $1))) + (nonterminal + ((SYMBOL + (setq semantic-grammar-wy--nterm $1 semantic-grammar-wy--rindx 0) + COLON rules SEMI) + (wisent-raw-tag + (semantic-tag $1 'nonterminal :children $4)))) + (rules + ((lifo_rules) + (apply #'nconc + (nreverse $1)))) + (lifo_rules + ((lifo_rules OR rule) + (cons $3 $1)) + ((rule) + (list $1))) + (rule + ((rhs) + (let* + ((nterm semantic-grammar-wy--nterm) + (rindx semantic-grammar-wy--rindx) + (rhs $1) + comps prec action elt) + (setq semantic-grammar-wy--rindx + (1+ semantic-grammar-wy--rindx)) + (while rhs + (setq elt + (car rhs) + rhs + (cdr rhs)) + (cond + ((vectorp elt) + (if prec + (error "Duplicate %%prec in `%s:%d' rule" nterm rindx)) + (setq prec + (aref elt 0))) + ((consp elt) + (if + (or action comps) + (setq comps + (cons elt comps) + semantic-grammar-wy--rindx + (1+ semantic-grammar-wy--rindx)) + (setq action + (car elt)))) + (t + (setq comps + (cons elt comps))))) + (wisent-cook-tag + (wisent-raw-tag + (semantic-tag + (format "%s:%d" nterm rindx) + 'rule :type + (if comps "group" "empty") + :value comps :prec prec :expr action)))))) + (rhs + (nil) + ((rhs item) + (cons $2 $1)) + ((rhs action) + (cons + (list $2) + $1)) + ((rhs PREC item) + (cons + (vector $3) + $1))) + (action + ((PAREN_BLOCK)) + ((PREFIXED_LIST)) + ((BRACE_BLOCK) + (format "(progn\n%s)" + (let + ((s $1)) + (if + (string-match "^{[ \n ]*" s) + (setq s + (substring s + (match-end 0)))) + (if + (string-match "[ \n ]*}$" s) + (setq s + (substring s 0 + (match-beginning 0)))) + s)))) + (items + ((lifo_items) + (nreverse $1))) + (lifo_items + ((lifo_items item) + (cons $2 $1)) + ((item) + (list $1))) + (item + ((SYMBOL)) + ((CHARACTER)))) + (grammar prologue epilogue declaration nonterminal rule put_names put_values use_names)) + "Parser table.") + +(defun semantic-grammar-wy--install-parser () + "Setup the Semantic Parser." + (semantic-install-function-overrides + '((semantic-parse-stream . wisent-parse-stream))) + (setq semantic-parser-name "LALR" + semantic--parse-table semantic-grammar-wy--parse-table + semantic-debug-parser-source "grammar.wy" + semantic-flex-keywords-obarray semantic-grammar-wy--keyword-table + semantic-lex-types-obarray semantic-grammar-wy--token-table) + ;; Collect unmatched syntax lexical tokens + (add-hook 'wisent-discarding-token-functions + #'wisent-collect-unmatched-syntax nil t)) + + +;;; Analyzers +;; +(define-lex-regex-type-analyzer semantic-grammar-wy---regexp-analyzer + "regexp analyzer for tokens." + ":?\\(\\sw\\|\\s_\\)+" + '((PERCENT_PERCENT . "\\`%%\\'")) + 'SYMBOL) + +(define-lex-keyword-type-analyzer semantic-grammar-wy---keyword-analyzer + "keyword analyzer for tokens." + "\\(\\sw\\|\\s_\\)+") + +(define-lex-regex-type-analyzer semantic-grammar-wy---regexp-analyzer + "regexp analyzer for tokens." + semantic-grammar-lex-c-char-re + nil + 'CHARACTER) + +(define-lex-sexp-type-analyzer semantic-grammar-wy---sexp-analyzer + "sexp analyzer for tokens." + "\\s'\\s-*(" + 'PREFIXED_LIST) + +(define-lex-block-type-analyzer semantic-grammar-wy---block-analyzer + "block analyzer for tokens." + "\\s(\\|\\s)" + '((("(" LPAREN PAREN_BLOCK) + ("{" LBRACE BRACE_BLOCK)) + (")" RPAREN) + ("}" RBRACE)) + ) + +(define-lex-string-type-analyzer semantic-grammar-wy---string-analyzer + "string analyzer for tokens." + "\\(\\s.\\|\\s$\\|\\s'\\)+" + '((GT . ">") + (LT . "<") + (OR . "|") + (SEMI . ";") + (COLON . ":")) + 'punctuation) + +(define-lex-sexp-type-analyzer semantic-grammar-wy---sexp-analyzer + "sexp analyzer for tokens." + "\\s\"" + 'STRING) + +(define-lex-sexp-type-analyzer semantic-grammar-wy---sexp-analyzer + "sexp analyzer for tokens." + "\\=" + 'SEXP) + + +;;; Epilogue +;; + + + + +(provide 'semantic/grammar-wy) + +;; Local Variables: +;; version-control: never +;; no-update-autoloads: t +;; End: + +;;; semantic/grammar-wy.el ends here diff --git a/lisp/emacs-lisp/eieio-base.el b/lisp/emacs-lisp/eieio-base.el index ec1077d447e..641882c9026 100644 --- a/lisp/emacs-lisp/eieio-base.el +++ b/lisp/emacs-lisp/eieio-base.el @@ -1,7 +1,6 @@ ;;; eieio-base.el --- Base classes for EIEIO. -*- lexical-binding:t -*- -;;; Copyright (C) 2000-2002, 2004-2005, 2007-2021 Free Software -;;; Foundation, Inc. +;; Copyright (C) 2000-2021 Free Software Foundation, Inc. ;; Author: Eric M. Ludlam ;; Keywords: OO, lisp -- cgit v1.2.3