diff options
66 files changed, 503 insertions, 67 deletions
diff --git a/Makefile.in b/Makefile.in index 28567ddaa5..cc92df3a21 100644 --- a/Makefile.in +++ b/Makefile.in @@ -294,6 +294,13 @@ RELEASE_ROOT = $(TESTROOT) endif endif +# ---------------------------------------------------------------------- + +ifeq ($(ERL_DETERMINISTIC),yes) + DETERMINISM_FLAG = +deterministic +else + DETERMINISM_FLAG = +endif # ---------------------------------------------------------------------- @@ -1036,7 +1043,7 @@ primary_bootstrap: primary_bootstrap_build: primary_bootstrap_mkdirs primary_bootstrap_compiler \ primary_bootstrap_stdlib - $(make_verbose)cd lib && $(MAKE) ERLC_FLAGS='-pa $(BOOTSTRAP_COMPILER)/ebin' \ + $(make_verbose)cd lib && $(MAKE) ERLC_FLAGS='-pa $(BOOTSTRAP_COMPILER)/ebin $(DETERMINISM_FLAG)' \ BOOTSTRAP_TOP=$(BOOTSTRAP_TOP) \ BOOTSTRAP=1 opt @@ -139,6 +139,10 @@ while test $# != 0; do pie_cflags="-fno-PIE" pie_ldflags="-no-pie" ;; + --enable-deterministic-build) + config_arguments="$config_arguments --enable-deterministic-build";; + --disable-deterministic-build) + config_arguments="$config_arguments --disable-deterministic-build";; CFLAGS=* | LDFLAGS=*) flgs_var=`echo "$1" | sed 's/=.*$//'` flgs_val=`echo "$1" | sed 's/^[^=]*=//'` diff --git a/configure.src b/configure.src index f0afd5c6ee..1a24bfc693 100644 --- a/configure.src +++ b/configure.src @@ -139,6 +139,10 @@ while test $# != 0; do pie_cflags="-fno-PIE" pie_ldflags="-no-pie" ;; + --enable-deterministic-build) + config_arguments="$config_arguments --enable-deterministic-build";; + --disable-deterministic-build) + config_arguments="$config_arguments --disable-deterministic-build";; CFLAGS=* | LDFLAGS=*) flgs_var=`echo "$1" | sed 's/=.*$//'` flgs_val=`echo "$1" | sed 's/^[^=]*=//'` diff --git a/erts/configure b/erts/configure index a287a59d20..dcc45bffe4 100755 --- a/erts/configure +++ b/erts/configure @@ -650,6 +650,7 @@ ac_func_c_list= ac_subst_vars='LTLIBOBJS LIBOBJS DEBUG_CFLAGS +ERL_DETERMINISTIC CFLAGS32 CC32 JAVAC @@ -868,6 +869,7 @@ enable_prefer_elapsed_monotonic_time_during_suspend enable_gettimeofday_as_os_system_time with_javac enable_sanitizers +enable_deterministic_build ' ac_precious_vars='build_alias host_alias @@ -1610,6 +1612,9 @@ Optional Features: Force usage of gettimeofday() for OS system time --enable-sanitizers[=comma-separated list of sanitizers] Default=address,undefined + --enable-deterministic-build + enable build determinism, stripping absolute paths + from build output Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] @@ -25658,6 +25663,20 @@ LDFLAGS="$LDFLAGS $sanitizers" fi + +# Check whether --enable-deterministic-build was given. +if test ${enable_deterministic_build+y} +then : + enableval=$enable_deterministic_build; case "$enableval" in + no) ERL_DETERMINISTIC=no ;; + *) ERL_DETERMINISTIC=yes ;; + esac +else $as_nop + ERL_DETERMINISTIC=no +fi + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking CFLAGS for -O switch" >&5 printf %s "checking CFLAGS for -O switch... " >&6; } no_opt_CFLAGS=$(echo " $CFLAGS" | sed 's/ -O[^ ]*/ /g') diff --git a/erts/configure.ac b/erts/configure.ac index d96c28d9b8..ece99e4e7a 100644 --- a/erts/configure.ac +++ b/erts/configure.ac @@ -3570,6 +3570,19 @@ CFLAGS="$CFLAGS $sanitizers" LDFLAGS="$LDFLAGS $sanitizers" ]) +dnl ---------------------------------------------------------------------- +dnl Enable build determinism flag +dnl ---------------------------------------------------------------------- + +AC_ARG_ENABLE(deterministic-build, +AS_HELP_STRING([--enable-deterministic-build], [enable build determinism, stripping absolute paths from build output]), +[ case "$enableval" in + no) ERL_DETERMINISTIC=no ;; + *) ERL_DETERMINISTIC=yes ;; + esac ], +ERL_DETERMINISTIC=no) +AC_SUBST(ERL_DETERMINISTIC) + AC_MSG_CHECKING([CFLAGS for -O switch]) dnl Remove all "-O*" options no_opt_CFLAGS=$(echo " $CFLAGS" | sed 's/ -O[[^ ]]*/ /g') diff --git a/erts/emulator/test/Makefile b/erts/emulator/test/Makefile index 89ba1239d2..33a80f2e53 100644 --- a/erts/emulator/test/Makefile +++ b/erts/emulator/test/Makefile @@ -182,7 +182,7 @@ RELSYSDIR = $(RELEASE_PATH)/emulator_test # FLAGS # ---------------------------------------------------- ERL_MAKE_FLAGS += -ERL_COMPILE_FLAGS += +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$($(ERL_COMPILE_FLAGS))) # ---------------------------------------------------- # Targets diff --git a/erts/preloaded/src/Makefile b/erts/preloaded/src/Makefile index 191341a9f5..1994aa1302 100644 --- a/erts/preloaded/src/Makefile +++ b/erts/preloaded/src/Makefile @@ -86,6 +86,10 @@ STDLIB_INCLUDE=$(ERL_TOP)/lib/stdlib/include ERL_COMPILE_FLAGS += +debug_info -I$(KERNEL_SRC) -I$(KERNEL_INCLUDE) +ifeq ($(ERL_DETERMINISTIC),yes) + ERL_COMPILE_FLAGS += deterministic +endif + DIA_PLT = erts-preloaded.plt DIA_ANALYSIS = $(basename $(DIA_PLT)).dialyzer_analysis ifeq ($(DIAW_EH),true) diff --git a/erts/preloaded/src/add_abstract_code b/erts/preloaded/src/add_abstract_code index 9040199417..11add7773d 100644 --- a/erts/preloaded/src/add_abstract_code +++ b/erts/preloaded/src/add_abstract_code @@ -39,7 +39,12 @@ main([BeamFile,AbstrFile]) -> fix_options(CInf0) -> CInf1 = binary_to_term(CInf0), - {options,Opts0} = lists:keyfind(options, 1, CInf1), - Opts = Opts0 -- [from_asm], + Opts = + case lists:keyfind(options, 1, CInf1) of + {options,Opts0} -> + Opts0 -- [from_asm]; + false -> + [] + end, CInf = lists:keyreplace(options, 1, CInf1, {options,Opts}), {term_to_binary(CInf), Opts}. diff --git a/lib/asn1/doc/src/asn1ct.xml b/lib/asn1/doc/src/asn1ct.xml index e4c5a2a3ee..a9a71db629 100644 --- a/lib/asn1/doc/src/asn1ct.xml +++ b/lib/asn1/doc/src/asn1ct.xml @@ -83,7 +83,7 @@ legacy_bit_string | legacy_erlang_types | noobj | {n2n, EnumTypeName} |{outdir, Dir} | {i, IncludeDir} | asn1config | undec_rest | no_ok_wrapper | - {macro_name_prefix, Prefix} | {record_name_prefix, Prefix} | verbose | warnings_as_errors</v> + {macro_name_prefix, Prefix} | {record_name_prefix, Prefix} | verbose | warnings_as_errors | deterministic</v> <v>OldOption = ber | per</v> <v>Reason = term()</v> <v>Prefix = string()</v> @@ -346,6 +346,11 @@ File3.asn</pre> <item> <p>Causes warnings to be treated as errors.</p> </item> + <tag><c>deterministic</c></tag> + <item> + <p>Causes all non-deterministic options to be stripped from the + -asn1_info() attribute.</p> + </item> </taglist> <p>Any more option that is applied is passed to the final step when the generated <c>.erl</c> file is compiled. diff --git a/lib/asn1/src/Makefile b/lib/asn1/src/Makefile index 6d02075576..9e13d02c8a 100644 --- a/lib/asn1/src/Makefile +++ b/lib/asn1/src/Makefile @@ -102,7 +102,13 @@ ERL_COMPILE_FLAGS += \ -I$(ERL_TOP)/lib/stdlib \ -Werror -YRL_FLAGS = +ifeq ($(ERL_DETERMINISTIC),yes) + YRL_FLAGS = +deterministic + DETERMINISM_FLAG = +deterministic +else + YRL_FLAGS = + DETERMINISM_FLAG = +endif # ---------------------------------------------------- # Targets @@ -182,10 +188,10 @@ asn1ct_rtt.erl: prepare_templates.$(EMULATOR) $(RT_TEMPLATES_TARGET) $(RT_TEMPLATES_TARGET) prepare_templates.$(EMULATOR): prepare_templates.erl - $(V_ERLC) prepare_templates.erl + $(V_ERLC) $(DETERMINISM_FLAG) prepare_templates.erl asn1rtt_%.$(EMULATOR): asn1rtt_%.erl - $(V_ERLC) +debug_info $< + $(V_ERLC) +debug_info $(DETERMINISM_FLAG) $< $(EVAL_CT_MODULES:%=%.erl): prepare_templates.$(EMULATOR) \ $(EBIN)/asn1ct_rtt.$(EMULATOR) \ diff --git a/lib/asn1/src/asn1ct_gen.erl b/lib/asn1/src/asn1ct_gen.erl index 7f83ae63fd..88dc88487d 100644 --- a/lib/asn1/src/asn1ct_gen.erl +++ b/lib/asn1/src/asn1ct_gen.erl @@ -1327,9 +1327,25 @@ gen_head(#gen{options=Options}=Gen, Mod, Hrl) -> 0 -> ok; _ -> emit(["-include(\"",Mod,".hrl\").",nl]) end, + Deterministic = proplists:get_bool(deterministic, Options), + Options1 = + case Deterministic of + true -> + %% compile:keep_compile_option will filter some of these + %% out of generated .beam files, but this will keep + %% them out of the generated .erl files + lists:filter( + fun({cwd, _}) -> false; + ({outdir, _}) -> false; + ({i, _}) -> false; + (_) -> true end, + Options); + false -> + Options + end, emit(["-asn1_info([{vsn,'",asn1ct:vsn(),"'},",nl, " {module,'",Mod,"'},",nl, - " {options,",io_lib:format("~p",[Options]),"}]).",nl,nl]), + " {options,",io_lib:format("~p",[Options1]),"}]).",nl,nl]), JerDefines = case Gen of #gen{erule=jer} -> true; diff --git a/lib/asn1/test/Makefile b/lib/asn1/test/Makefile index 58f7b294f3..de2a38e752 100644 --- a/lib/asn1/test/Makefile +++ b/lib/asn1/test/Makefile @@ -138,6 +138,7 @@ RELSYSDIR = $(RELEASE_PATH)/asn1_test # FLAGS # ---------------------------------------------------- ERL_COMPILE_FLAGS += +warnings_as_errors +nowarn_export_all +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) EBIN = . # ---------------------------------------------------- diff --git a/lib/asn1/test/asn1_SUITE.erl b/lib/asn1/test/asn1_SUITE.erl index eeb5253c32..2a02f08a95 100644 --- a/lib/asn1/test/asn1_SUITE.erl +++ b/lib/asn1/test/asn1_SUITE.erl @@ -1062,7 +1062,8 @@ test_compile_options(Config) -> ok = test_compile_options:noobj(Config), ok = test_compile_options:record_name_prefix(Config), ok = test_compile_options:verbose(Config), - ok = test_compile_options:maps(Config). + ok = test_compile_options:maps(Config), + ok = test_compile_options:determinism(Config). testDoubleEllipses(Config) -> test(Config, fun testDoubleEllipses/3). testDoubleEllipses(Config, Rule, Opts) -> diff --git a/lib/asn1/test/test_compile_options.erl b/lib/asn1/test/test_compile_options.erl index f9997d37d0..45e8f39d39 100644 --- a/lib/asn1/test/test_compile_options.erl +++ b/lib/asn1/test/test_compile_options.erl @@ -22,10 +22,11 @@ -module(test_compile_options). -include_lib("common_test/include/ct.hrl"). +-include_lib("stdlib/include/assert.hrl"). -export([wrong_path/1,comp/2,path/1,noobj/1, - record_name_prefix/1,verbose/1,maps/1]). + record_name_prefix/1,verbose/1,maps/1,determinism/1]). %% OTP-5689 wrong_path(Config) -> @@ -150,6 +151,51 @@ do_maps(Erule, InFile, OutDir) -> ok. +determinism(Config) when is_list(Config) -> + DataDir = proplists:get_value(data_dir,Config), + OutDir = proplists:get_value(priv_dir,Config), + Asn1File = filename:join([DataDir,"Comment.asn"]), + ErlFile = filename:join([OutDir,"Comment.erl"]), + + ContainsNonDeterministicOptions = + fun + ({attribute,_Anno,asn1_info,Elems}) -> + lists:any( + fun + ({options, Opts}) -> + lists:any(fun ({i, _}) -> true; (_) -> false end, Opts) + andalso + lists:any(fun ({outdir, _}) -> true; (_) -> false end, Opts) + andalso + lists:any(fun ({cwd, _}) -> true; (_) -> false end, Opts); + (_) -> + false + end, + Elems); + (_) -> + false + end, + + BaseOptions = [{i,DataDir},{outdir,OutDir},{cwd,DataDir},noobj], + + %% Test deterministic compile + ok = asn1ct:compile(Asn1File, BaseOptions ++ [deterministic]), + {ok, List1} = epp:parse_file(ErlFile, [{includes, [DataDir]}, + {source_name, "Comment.erl"}]), + ?assertNot(lists:any(ContainsNonDeterministicOptions, List1), + "Expected no debugging option values (i, outdir, cwd) in asn1_info attribute " ++ + "in deterministic mode"), + + %% Test non-deterministic compile + ok = asn1ct:compile(Asn1File, BaseOptions), + {ok, List2} = epp:parse_file(ErlFile, [{includes, [DataDir]}, + {source_name, "Comment.erl"}]), + ?assert(lists:any(ContainsNonDeterministicOptions, List2), + "Expected debugging option values (i, outdir, cwd) in asn1_info attribute " ++ + "in non-deterministic mode"), + ok. + + outfiles_check(OutDir) -> outfiles_check(OutDir,outfiles1()). diff --git a/lib/common_test/test/Makefile b/lib/common_test/test/Makefile index 4cc10cbdcc..1af9990bb7 100644 --- a/lib/common_test/test/Makefile +++ b/lib/common_test/test/Makefile @@ -99,6 +99,7 @@ RELSYSDIR = $(RELEASE_PATH)/common_test_test ERL_MAKE_FLAGS += ERL_COMPILE_FLAGS += +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) EBIN = . diff --git a/lib/compiler/src/Makefile b/lib/compiler/src/Makefile index 57c099601d..8b124d138b 100644 --- a/lib/compiler/src/Makefile +++ b/lib/compiler/src/Makefile @@ -138,6 +138,12 @@ ERL_COMPILE_FLAGS += -Werror ERL_COMPILE_FLAGS += +inline +warn_unused_import \ -I../../stdlib/include -I$(EGEN) -W +warn_missing_spec +ifeq ($(ERL_DETERMINISTIC),yes) + DETERMINISM_FLAG = +deterministic +else + DETERMINISM_FLAG = +endif + # ---------------------------------------------------- # Targets # ---------------------------------------------------- diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl index da388e4bce..771be26765 100644 --- a/lib/compiler/src/compile.erl +++ b/lib/compiler/src/compile.erl @@ -1023,6 +1023,7 @@ do_parse_module(DefEncoding, #compile{ifile=File,options=Opts,dir=Dir}=St) -> R = epp:parse_file(File, [{includes,[".",Dir|inc_paths(Opts)]}, {source_name, SourceName}, + {deterministic, member(deterministic, Opts)}, {macros,pre_defs(Opts)}, {default_encoding,DefEncoding}, {location,StartLocation}, diff --git a/lib/compiler/test/Makefile b/lib/compiler/test/Makefile index 37fb570154..8e145ae136 100644 --- a/lib/compiler/test/Makefile +++ b/lib/compiler/test/Makefile @@ -168,6 +168,7 @@ RELSYSDIR = $(RELEASE_PATH)/compiler_test ERL_MAKE_FLAGS += ERL_COMPILE_FLAGS += +clint +clint0 +ssalint +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) EBIN = . diff --git a/lib/compiler/test/test_lib.erl b/lib/compiler/test/test_lib.erl index 4f24310d15..7182dd6555 100644 --- a/lib/compiler/test/test_lib.erl +++ b/lib/compiler/test/test_lib.erl @@ -82,7 +82,8 @@ uniq() -> opt_opts(Mod) -> Comp = Mod:module_info(compile), - {options,Opts} = lists:keyfind(options, 1, Comp), + %% `options` may not be set at all if +deterministic is enabled. + Opts = proplists:get_value(options, Comp, []), lists:filter(fun (debug_info) -> true; (dialyzer) -> true; diff --git a/lib/debugger/test/Makefile b/lib/debugger/test/Makefile index 14186798f0..015b5f9c29 100644 --- a/lib/debugger/test/Makefile +++ b/lib/debugger/test/Makefile @@ -71,6 +71,7 @@ RELSYSDIR = $(RELEASE_PATH)/debugger_test ERL_MAKE_FLAGS += ERL_COMPILE_FLAGS += +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) EBIN = . diff --git a/lib/diameter/src/Makefile b/lib/diameter/src/Makefile index 6dd3667a46..75e23d4191 100644 --- a/lib/diameter/src/Makefile +++ b/lib/diameter/src/Makefile @@ -122,6 +122,12 @@ ERL_COMPILE_FLAGS += \ # -pa is to be able to include_lib from the include directory: the # path must contain the application name. +ifeq ($(ERL_DETERMINISTIC),yes) + DETERMINISM_FLAG = +deterministic +else + DETERMINISM_FLAG = +endif + # ---------------------------------------------------- # Targets # ---------------------------------------------------- @@ -152,7 +158,7 @@ $(filter-out opt, $(TYPES)): # The dictionary parser. gen/$(DICT_YRL).erl: compiler/$(DICT_YRL).yrl $(yecc_verbose) \ - $(ERLC) -Werror -o $(@D) $< + $(ERLC) -Werror $(DETERMINISM_FLAG) -o $(@D) $< # Generate the app file. $(APP_TARGET): $(APP_SRC) ../vsn.mk modules.mk @@ -256,8 +262,8 @@ release_spec: opt $(INSTALL_DATA) $(EXTERNAL_HRLS:%=../include/%) $(DICT_HRLS) \ "$(RELSYSDIR)/include" $(INSTALL_DATA) $(DICTS:%=dict/%.dia) "$(RELSYSDIR)/src/dict" - $(MAKE) $(TARGET_DIRS:%/=release_src_%) - $(MAKE) $(EXAMPLE_DIRS:%/=release_examples_%) + $(MAKE) ERL_DETERMINISTIC=$(ERL_DETERMINISTIC) $(TARGET_DIRS:%/=release_src_%) + $(MAKE) ERL_DETERMINISTIC=$(ERL_DETERMINISTIC) $(EXAMPLE_DIRS:%/=release_examples_%) $(TARGET_DIRS:%/=release_src_%): release_src_%: $(INSTALL_DIR) "$(RELSYSDIR)/src/$*" diff --git a/lib/diameter/test/Makefile b/lib/diameter/test/Makefile index 53b5fd4618..98fb9ff652 100644 --- a/lib/diameter/test/Makefile +++ b/lib/diameter/test/Makefile @@ -59,6 +59,7 @@ ERL_COMPILE_FLAGS += +warn_export_vars \ -I ../include \ -I ../src/gen \ $(STRICT_FLAGS) +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) # ---------------------------------------------------- # Targets diff --git a/lib/edoc/test/Makefile b/lib/edoc/test/Makefile index 80906a9456..139ba8b8bd 100644 --- a/lib/edoc/test/Makefile +++ b/lib/edoc/test/Makefile @@ -27,6 +27,7 @@ RELSYSDIR = $(RELEASE_PATH)/edoc_test ERL_MAKE_FLAGS += ERL_COMPILE_FLAGS += +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) EBIN = . diff --git a/lib/eldap/test/Makefile b/lib/eldap/test/Makefile index ba8fe0dfa9..61cad55c64 100644 --- a/lib/eldap/test/Makefile +++ b/lib/eldap/test/Makefile @@ -54,6 +54,7 @@ RELSYSDIR = $(RELEASE_PATH)/eldap_test # FLAGS # ---------------------------------------------------- ERL_COMPILE_FLAGS += $(INCLUDES) -pa $(ERL_TOP)/lib/eldap/ebin +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) EBIN = . diff --git a/lib/erl_docgen/test/Makefile b/lib/erl_docgen/test/Makefile index fe45b2a684..9af7824553 100644 --- a/lib/erl_docgen/test/Makefile +++ b/lib/erl_docgen/test/Makefile @@ -26,6 +26,7 @@ RELSYSDIR = $(RELEASE_PATH)/erl_docgen_test ERL_MAKE_FLAGS += ERL_COMPILE_FLAGS += +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) EBIN = . diff --git a/lib/eunit/test/Makefile b/lib/eunit/test/Makefile index e2fbdf7241..1bd9c0a07c 100644 --- a/lib/eunit/test/Makefile +++ b/lib/eunit/test/Makefile @@ -45,6 +45,7 @@ RELSYSDIR = $(RELEASE_PATH)/eunit_test # ---------------------------------------------------- ERL_MAKE_FLAGS += ERL_COMPILE_FLAGS += +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) EBIN = . diff --git a/lib/ftp/test/Makefile b/lib/ftp/test/Makefile index 71ddb3bc7c..4686d8f1bd 100644 --- a/lib/ftp/test/Makefile +++ b/lib/ftp/test/Makefile @@ -152,6 +152,7 @@ RELTESTSYSBINDIR = $(RELTESTSYSALLDATADIR)/bin ERL_COMPILE_FLAGS += \ $(INCLUDES) \ $(FTP_FLAGS) +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) # ---------------------------------------------------- # Targets diff --git a/lib/inets/test/Makefile b/lib/inets/test/Makefile index 16a1abaee7..414884a535 100644 --- a/lib/inets/test/Makefile +++ b/lib/inets/test/Makefile @@ -200,6 +200,7 @@ RELTESTSYSBINDIR = $(RELTESTSYSALLDATADIR)/bin ERL_COMPILE_FLAGS += \ $(INCLUDES) \ $(INETS_FLAGS) +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) # ---------------------------------------------------- # Targets diff --git a/lib/kernel/test/Makefile b/lib/kernel/test/Makefile index 12e6c42f7c..130e626b56 100644 --- a/lib/kernel/test/Makefile +++ b/lib/kernel/test/Makefile @@ -159,6 +159,7 @@ RELSYSDIR = $(RELEASE_PATH)/kernel_test ERL_MAKE_FLAGS += ERL_COMPILE_FLAGS += +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) EBIN = . diff --git a/lib/megaco/Makefile b/lib/megaco/Makefile index 5dc2955dd8..a1b7adc924 100644 --- a/lib/megaco/Makefile +++ b/lib/megaco/Makefile @@ -98,7 +98,13 @@ else FLEX_SCANNER_REENTRANT_ENABLER = --enable-megaco-reentrant-flex-scanner endif -CONFIGURE_OPTS = $(FLEX_SCANNER_LINENO_ENABLER) $(FLEX_SCANNER_REENTRANT_ENABLER) +ifeq ($(ERL_DETERMINISTIC),yes) + ERL_DETERMINISTIC_ENABLER = --enable-deterministic-build +else + ERL_DETERMINISTIC_ENABLER = --disable-deterministic-build +endif + +CONFIGURE_OPTS = $(FLEX_SCANNER_LINENO_ENABLER) $(FLEX_SCANNER_REENTRANT_ENABLER) $(ERL_DETERMINISTIC_ENABLER) DIA_PLT = ./priv/plt/$(APPLICATION).plt @@ -115,7 +121,7 @@ include $(ERL_TOP)/make/otp_subdir.mk reconf: (cd $(ERL_TOP) && \ - ./otp_build configure && \ + ./otp_build configure $(ERL_DETERMINISTIC_ENABLER) && \ cd $(ERL_TOP)/../libraries/megaco) conf: do_configure diff --git a/lib/megaco/src/app/megaco.mk b/lib/megaco/src/app/megaco.mk index a887dd42bc..d42fd0d7ed 100644 --- a/lib/megaco/src/app/megaco.mk +++ b/lib/megaco/src/app/megaco.mk @@ -42,6 +42,12 @@ ifeq ($(WARN_UNUSED_WARS), true) ERL_COMPILE_FLAGS += +warn_unused_vars endif +ifeq ($(ERL_DETERMINISTIC),yes) +ERL_COMPILE_FLAGS += +deterministic +YRL_FLAGS += +deterministic +XRL_FLAGS += +deterministic +endif + MEGACO_APP_VSN_COMPILE_FLAGS = \ +'{parse_transform,sys_pre_attributes}' \ +'{attribute,insert,app_vsn,$(APP_VSN)}' diff --git a/lib/megaco/src/binary/depend.mk b/lib/megaco/src/binary/depend.mk index ca2872975c..d430d157c0 100644 --- a/lib/megaco/src/binary/depend.mk +++ b/lib/megaco/src/binary/depend.mk @@ -35,6 +35,10 @@ ifeq ($(MEGACO_INLINE_ASN1_RT),true) ASN1_CT_OPTS += +inline endif +ifeq ($(ERL_DETERMINISTIC),yes) +ASN1_CT_OPTS += +deterministic +endif + BER_V1_FLAGS = $(ASN1_CT_OPTS) +asn1config BER_V2_FLAGS = $(ASN1_CT_OPTS) +asn1config BER_V3_FLAGS = $(ASN1_CT_OPTS) +asn1config diff --git a/lib/megaco/test/Makefile b/lib/megaco/test/Makefile index 57437e50a6..eced232a47 100644 --- a/lib/megaco/test/Makefile +++ b/lib/megaco/test/Makefile @@ -90,6 +90,8 @@ ERL_COMPILE_FLAGS += $(MEGACO_ERL_COMPILE_FLAGS) # We have a behaviour in the test catalog (megaco_test_generator) ERL_COMPILE_FLAGS += -pa ../../megaco/test +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) + ERL_PATH = -pa ../../megaco/examples/simple \ -pa ../../megaco/ebin \ -pa ../../et/ebin diff --git a/lib/mnesia/test/Makefile b/lib/mnesia/test/Makefile index 378bcc44d0..c3fbad88ca 100644 --- a/lib/mnesia/test/Makefile +++ b/lib/mnesia/test/Makefile @@ -91,6 +91,7 @@ RELSYSDIR = $(RELEASE_PATH)/mnesia_test # FLAGS # ---------------------------------------------------- #ERL_COMPILE_FLAGS += +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) EBIN = . diff --git a/lib/observer/test/Makefile b/lib/observer/test/Makefile index 8c7ca2fcfc..114f77400f 100644 --- a/lib/observer/test/Makefile +++ b/lib/observer/test/Makefile @@ -52,6 +52,7 @@ RELSYSDIR = $(RELEASE_PATH)/observer_test # ---------------------------------------------------- ERL_MAKE_FLAGS += ERL_COMPILE_FLAGS += +warnings_as_errors +nowarn_export_all +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) EBIN = . diff --git a/lib/odbc/test/Makefile b/lib/odbc/test/Makefile index 87caa54c61..ab184ac06b 100644 --- a/lib/odbc/test/Makefile +++ b/lib/odbc/test/Makefile @@ -72,6 +72,8 @@ RELSYSDIR = $(RELEASE_PATH)/odbc_test ERL_COMPILE_FLAGS += $(INCLUDES) \ +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) + # ---------------------------------------------------- # Targets # ---------------------------------------------------- diff --git a/lib/os_mon/test/Makefile b/lib/os_mon/test/Makefile index d8dc4e57c7..df7b606c06 100644 --- a/lib/os_mon/test/Makefile +++ b/lib/os_mon/test/Makefile @@ -55,6 +55,7 @@ RELSYSDIR = $(RELEASE_PATH)/os_mon_test # ---------------------------------------------------- ERL_MAKE_FLAGS += ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/snmp/include +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) # ---------------------------------------------------- # Targets diff --git a/lib/parsetools/doc/src/leex.xml b/lib/parsetools/doc/src/leex.xml index 357ed86f44..d802e46b59 100644 --- a/lib/parsetools/doc/src/leex.xml +++ b/lib/parsetools/doc/src/leex.xml @@ -110,6 +110,11 @@ <item> <p>Causes warnings to be treated as errors.</p> </item> + <tag><c>{deterministic, boolean()}</c></tag> + <item> + <p>Causes generated -file() attributes to only include + the basename of the file path.</p> + </item> </taglist> <p>Any of the Boolean options can be set to <c>true</c> by stating the name of the option. For example, <c>verbose</c> diff --git a/lib/parsetools/doc/src/yecc.xml b/lib/parsetools/doc/src/yecc.xml index 218cec5330..4d639d1f21 100644 --- a/lib/parsetools/doc/src/yecc.xml +++ b/lib/parsetools/doc/src/yecc.xml @@ -134,6 +134,11 @@ is <c>column</c>, the location includes a line number and a column number. Default is <c>column</c>. </item> + <tag><c>{deterministic, boolean()}</c></tag> + <item> + <p>Causes generated -file() attributes to only include the + basename of the file path.</p> + </item> </taglist> <p>Any of the Boolean options can be set to <c>true</c> by stating the name of the option. For example, <c>verbose</c> diff --git a/lib/parsetools/src/leex.erl b/lib/parsetools/src/leex.erl index 15803b3b82..b764678516 100644 --- a/lib/parsetools/src/leex.erl +++ b/lib/parsetools/src/leex.erl @@ -78,9 +78,10 @@ compile(Input0, Output0, Output = assure_extension(shorten_filename(Output0), ".erl"), Includefile = lists:sublist(Includes, 1), Werror = proplists:get_bool(warnings_as_errors, Specific), + Deterministic = proplists:get_bool(deterministic, Specific), Opts = [{scannerfile,Output},{includefile,Includefile},{verbose,Verbose}, {report_errors,true},{report_warnings,WarnLevel > 0}, - {warnings_as_errors, Werror}], + {warnings_as_errors, Werror}, {deterministic, Deterministic}], case file(Input, Opts) of {ok, _} -> ok; @@ -117,6 +118,7 @@ file(File) -> file(File, []). | {'scannerfile', Scannerfile :: file:filename()} | {'verbose', boolean()} | {'warnings_as_errors', boolean()} + | {'deterministic', boolean()} | 'dfa_graph' | 'report_errors' | 'report_warnings' | 'report' | 'return_errors' | 'return_warnings' | 'return' @@ -287,7 +289,7 @@ check_options(_Options, _, _L) -> all_options() -> [dfa_graph,includefile,report_errors,report_warnings, return_errors,return_warnings,scannerfile,verbose, - warnings_as_errors]. + warnings_as_errors, deterministic]. default_option(dfa_graph) -> false; default_option(includefile) -> []; @@ -297,7 +299,8 @@ default_option(return_errors) -> false; default_option(return_warnings) -> false; default_option(scannerfile) -> []; default_option(verbose) -> false; -default_option(warnings_as_errors) -> false. +default_option(warnings_as_errors) -> false; +default_option(deterministic) -> false. atom_option(dfa_graph) -> {dfa_graph,true}; atom_option(report_errors) -> {report_errors,true}; @@ -306,6 +309,7 @@ atom_option(warnings_as_errors) -> {warnings_as_errors,true}; atom_option(return_errors) -> {return_errors,true}; atom_option(verbose) -> {verbose,true}; atom_option(return_warnings) -> {return_warnings,true}; +atom_option(deterministic) -> {deterministic,true}; atom_option(Key) -> Key. is_filename(T) -> @@ -1362,7 +1366,8 @@ out_file(St0, DFA, DF, Actions, Code) -> set_encoding(St0, Ofile), try output_encoding_comment(Ofile, St0), - output_file_directive(Ofile, St0#leex.ifile, 0), + Deterministic = proplists:get_bool(deterministic, St0#leex.opts), + output_file_directive(Ofile, St0#leex.ifile, Deterministic, 0), out_file(Ifile, Ofile, St0, DFA, DF, Actions, Code, 1), verbose_print(St0, "ok~n", []), @@ -1400,15 +1405,18 @@ inc_file_name(Filename) -> %% characters. out_file(Ifile, Ofile, St, DFA, DF, Actions, Code, L) -> + Deterministic = proplists:get_bool(deterministic, St#leex.opts), case io:get_line(Ifile, leex) of - eof -> output_file_directive(Ofile, St#leex.ifile, L); - {error, _} -> add_error(St#leex.ifile, {L, leex, cannot_parse}, St); + eof -> + output_file_directive(Ofile, St#leex.ifile, Deterministic, L); + {error, _} -> + add_error(St#leex.ifile, {L, leex, cannot_parse}, St); Line -> case string:slice(Line, 0, 5) of "##mod" -> out_module(Ofile, St); "##cod" -> out_erlang_code(Ofile, St, Code, L); "##dfa" -> out_dfa(Ofile, St, DFA, Code, DF, L); - "##act" -> out_actions(Ofile, St#leex.xfile, Actions); + "##act" -> out_actions(Ofile, St#leex.xfile, Deterministic, Actions); _ -> io:put_chars(Ofile, Line) end, out_file(Ifile, Ofile, St, DFA, DF, Actions, Code, L+1) @@ -1419,7 +1427,8 @@ out_module(File, St) -> out_erlang_code(File, St, Code, L) -> {CodeL,CodePos,_NCodeLines} = Code, - output_file_directive(File, St#leex.xfile, CodeL), + Deterministic = proplists:get_bool(deterministic, St#leex.opts), + output_file_directive(File, St#leex.xfile, Deterministic, CodeL), {ok,Xfile} = file:open(St#leex.xfile, [read]), try set_encoding(St, Xfile), @@ -1429,7 +1438,7 @@ out_erlang_code(File, St, Code, L) -> ok = file:close(Xfile) end, io:nl(File), - output_file_directive(File, St#leex.ifile, L). + output_file_directive(File, St#leex.ifile, Deterministic, L). file_copy(From, To) -> case io:get_line(From, leex) of @@ -1441,8 +1450,9 @@ file_copy(From, To) -> out_dfa(File, St, DFA, Code, DF, L) -> {_CodeL,_CodePos,NCodeLines} = Code, + Deterministic = proplists:get_bool(deterministic, St#leex.opts), %% Three file attributes before this one... - output_file_directive(File, St#leex.efile, L+(NCodeLines-1)+3), + output_file_directive(File, St#leex.efile, Deterministic, L+(NCodeLines-1)+3), io:fwrite(File, "yystate() -> ~w.~n~n", [DF]), foreach(fun (S) -> out_trans(File, S) end, DFA), io:fwrite(File, "yystate(S, Ics, Line, Tlen, Action, Alen) ->~n", []), @@ -1565,14 +1575,14 @@ pack_trans([Tr|Trs], Pt) -> % The default uninteresting case pack_trans(Trs, Pt ++ [Tr]); pack_trans([], Pt) -> Pt. -%% out_actions(File, XrlFile, ActionList) -> ok. +%% out_actions(File, XrlFile, Deterministic, ActionList) -> ok. %% Write out the action table. -out_actions(File, XrlFile, As) -> +out_actions(File, XrlFile, Deterministic, As) -> As1 = prep_out_actions(As), foreach(fun (A) -> out_action(File, A) end, As1), io:fwrite(File, "yyaction(_, _, _, _) -> error.~n", []), - foreach(fun (A) -> out_action_code(File, XrlFile, A) end, As1). + foreach(fun (A) -> out_action_code(File, XrlFile, Deterministic, A) end, As1). prep_out_actions(As) -> map(fun ({A,empty_action}) -> @@ -1603,14 +1613,14 @@ out_action(File, {A,_Code,Vars,Name,_Args,ArgsChars}) -> end, io:fwrite(File, " ~s(~s);~n", [Name, ArgsChars]). -out_action_code(_File, _XrlFile, {_A,empty_action}) -> +out_action_code(_File, _XrlFile, _Deterministic, {_A,empty_action}) -> ok; -out_action_code(File, XrlFile, {_A,Code,_Vars,Name,Args,ArgsChars}) -> +out_action_code(File, XrlFile, Deterministic, {_A,Code,_Vars,Name,Args,ArgsChars}) -> %% Should set the file to the .erl file, but instead assumes that %% ?LEEXINC is syntactically correct. io:fwrite(File, "\n-compile({inline,~w/~w}).\n", [Name, length(Args)]), L = erl_scan:line(hd(Code)), - output_file_directive(File, XrlFile, L-2), + output_file_directive(File, XrlFile, Deterministic, L-2), io:fwrite(File, "~s(~s) ->~n", [Name, ArgsChars]), io:fwrite(File, " ~ts\n", [pp_tokens(Code, L, File)]). @@ -1710,12 +1720,18 @@ output_encoding_comment(_File, #leex{encoding = none}) -> output_encoding_comment(File, #leex{encoding = Encoding}) -> io:fwrite(File, <<"%% ~s\n">>, [epp:encoding_to_string(Encoding)]). -output_file_directive(File, Filename, Line) -> +output_file_directive(File, Filename, Deterministic, Line) -> io:fwrite(File, <<"-file(~ts, ~w).\n">>, - [format_filename(Filename, File), Line]). - -format_filename(Filename0, File) -> - Filename = filename:flatten(Filename0), + [format_filename(Filename, File, Deterministic), Line]). + +format_filename(Filename0, File, Deterministic) -> + Filename = + case Deterministic of + true -> + filename:basename(filename:flatten(Filename0)); + false -> + filename:flatten(Filename0) + end, case enc(File) of unicode -> io_lib:write_string(Filename); latin1 -> io_lib:write_string_as_latin1(Filename) diff --git a/lib/parsetools/src/yecc.erl b/lib/parsetools/src/yecc.erl index 5b2a9efe4d..7833c6a120 100644 --- a/lib/parsetools/src/yecc.erl +++ b/lib/parsetools/src/yecc.erl @@ -141,9 +141,10 @@ compile(Input0, Output0, Output = shorten_filename(Output0), Includefile = lists:sublist(Includes, 1), Werror = proplists:get_bool(warnings_as_errors, Specific), + Deterministic = proplists:get_bool(deterministic, Specific), Opts = [{parserfile,Output}, {includefile,Includefile}, {verbose,Verbose}, {report_errors, true}, {report_warnings, WarnLevel > 0}, - {warnings_as_errors, Werror}], + {warnings_as_errors, Werror}, {deterministic, Deterministic}], case file(Input, Opts) of {ok, _OutFile} -> ok; @@ -265,6 +266,7 @@ file(GrammarFile) -> | {'parserfile', Parserfile :: file:filename()} | {'verbose', boolean()} | {'warnings_as_errors', boolean()} + | {'deterministic', boolean()} | 'report_errors' | 'report_warnings' | 'report' | 'return_errors' | 'return_warnings' | 'return' | 'verbose' | 'warnings_as_errors'. @@ -407,7 +409,7 @@ check_options(_Options, _, _L) -> all_options() -> [error_location, file_attributes, includefile, parserfile, report_errors, report_warnings, return_errors, return_warnings, - time, verbose, warnings_as_errors]. + time, verbose, warnings_as_errors, deterministic]. default_option(error_location) -> column; default_option(file_attributes) -> true; @@ -419,7 +421,8 @@ default_option(return_errors) -> false; default_option(return_warnings) -> false; default_option(time) -> false; default_option(verbose) -> false; -default_option(warnings_as_errors) -> false. +default_option(warnings_as_errors) -> false; +default_option(deterministic) -> false. atom_option(file_attributes) -> {file_attributes, true}; atom_option(report_errors) -> {report_errors, true}; @@ -429,6 +432,7 @@ atom_option(return_warnings) -> {return_warnings, true}; atom_option(time) -> {time, true}; atom_option(verbose) -> {verbose, true}; atom_option(warnings_as_errors) -> {warnings_as_errors, true}; +atom_option(deterministic) -> {deterministic, true}; atom_option(Key) -> Key. is_filename(T) -> @@ -2695,7 +2699,12 @@ nl(#yecc{outport = Outport, line = Line}=St) -> St#yecc{line = Line + 1}. format_filename(Filename0, St) -> - Filename = filename:flatten(Filename0), + Deterministic = proplists:get_bool(deterministic, St#yecc.options), + Filename = + case Deterministic of + true -> filename:basename(filename:flatten(Filename0)); + false -> filename:flatten(Filename0) + end, case lists:keyfind(encoding, 1, io:getopts(St#yecc.outport)) of {encoding, unicode} -> io_lib:write_string(Filename); _ -> io_lib:write_string_as_latin1(Filename) diff --git a/lib/parsetools/test/Makefile b/lib/parsetools/test/Makefile index d494953f1e..23cb9709e1 100644 --- a/lib/parsetools/test/Makefile +++ b/lib/parsetools/test/Makefile @@ -42,6 +42,7 @@ RELSYSDIR = $(RELEASE_PATH)/parsetools_test # ---------------------------------------------------- ERL_MAKE_FLAGS += ERL_COMPILE_FLAGS += +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) EBIN = . diff --git a/lib/parsetools/test/leex_SUITE.erl b/lib/parsetools/test/leex_SUITE.erl index 09a6e026bd..bef048dc82 100644 --- a/lib/parsetools/test/leex_SUITE.erl +++ b/lib/parsetools/test/leex_SUITE.erl @@ -22,6 +22,7 @@ %-define(debug, true). -include_lib("stdlib/include/erl_compile.hrl"). +-include_lib("stdlib/include/assert.hrl"). -include_lib("kernel/include/file.hrl"). -ifdef(debug). @@ -39,7 +40,7 @@ init_per_testcase/2, end_per_testcase/2]). -export([ - file/1, compile/1, syntax/1, + file/1, compile/1, syntax/1, deterministic/1, pt/1, man/1, ex/1, ex2/1, not_yet/1, line_wrap/1, @@ -64,7 +65,7 @@ all() -> [{group, checks}, {group, examples}, {group, tickets}, {group, bugs}]. groups() -> - [{checks, [], [file, compile, syntax]}, + [{checks, [], [file, compile, syntax, deterministic]}, {examples, [], [pt, man, ex, ex2, not_yet, unicode]}, {tickets, [], [otp_10302, otp_11286, otp_13916, otp_14285, otp_17023, compiler_warnings]}, @@ -368,6 +369,42 @@ syntax(Config) when is_list(Config) -> leex:file(Filename, Ret), ok. +deterministic(doc) -> + "Check leex respects the +deterministic flag."; +deterministic(suite) -> []; +deterministic(Config) when is_list(Config) -> + Dir = ?privdir, + Filename = filename:join(Dir, "file.xrl"), + Scannerfile = filename:join(Dir, "file.erl"), + Mini = <<"Definitions.\n" + "D = [0-9]\n" + "Rules.\n" + "{L}+ : {token,{word,TokenLine,TokenChars}}.\n" + "Erlang code.\n">>, + ok = file:write_file(Filename, Mini), + + %% Generated leex scanners include the leexinc.hrl header file by default, + %% so we'll get a -file attribute corresponding to that include. In + %% deterministic mode, that include should only use the basename, + %% "leexinc.hrl", but otherwise, it should contain the full path. + + %% Matches when OTP is not installed (e.g. /lib/parsetools/include/leexinc.hrl) + %% and when it is (e.g. /lib/parsetools-2.3.2/include/leexinc.hrl) + AbsolutePathSuffix = ".*/lib/parsetools.*/include/leexinc\.hrl", + + ok = leex:compile(Filename, Scannerfile, #options{specific=[deterministic]}), + {ok, FormsDet} = epp:parse_file(Scannerfile,[]), + ?assertMatch(false, search_for_file_attr(AbsolutePathSuffix, FormsDet)), + ?assertMatch({value, _}, search_for_file_attr("leexinc\.hrl", FormsDet)), + file:delete(Scannerfile), + + ok = leex:compile(Filename, Scannerfile, #options{}), + {ok, Forms} = epp:parse_file(Scannerfile,[]), + ?assertMatch({value, _}, search_for_file_attr(AbsolutePathSuffix, Forms)), + file:delete(Scannerfile), + + file:delete(Filename), + ok. pt(doc) -> "Pushing back characters."; @@ -1272,3 +1309,13 @@ extract(File, {error, Es, Ws}) -> {errors, extract(File, Es), extract(File, Ws)}; extract(File, Ts) -> lists:append([T || {F, T} <- Ts, F =:= File]). + +search_for_file_attr(PartialFilePathRegex, Forms) -> + lists:search(fun + ({attribute, _, file, {FileAttr, _}}) -> + case re:run(FileAttr, PartialFilePathRegex) of + nomatch -> false; + _ -> true + end; + (_) -> false end, + Forms). diff --git a/lib/parsetools/test/yecc_SUITE.erl b/lib/parsetools/test/yecc_SUITE.erl index c0f03edd9e..e76b98f0f5 100644 --- a/lib/parsetools/test/yecc_SUITE.erl +++ b/lib/parsetools/test/yecc_SUITE.erl @@ -22,6 +22,7 @@ %-define(debug, true). -include_lib("stdlib/include/erl_compile.hrl"). +-include_lib("stdlib/include/assert.hrl"). -ifdef(debug). -define(config(X,Y), foo). @@ -40,7 +41,7 @@ -export([app_test/1, file/1, syntax/1, compile/1, rules/1, expect/1, - conflicts/1, + conflicts/1, deterministic/1, empty/1, prec/1, yeccpre/1, lalr/1, old_yecc/1, other_examples/1, @@ -70,7 +71,7 @@ all() -> groups() -> [{checks, [], - [file, syntax, compile, rules, expect, conflicts]}, + [file, syntax, compile, rules, expect, conflicts, deterministic]}, {examples, [], [empty, prec, yeccpre, lalr, old_yecc, other_examples]}, {bugs, [], @@ -926,6 +927,43 @@ conflicts(Config) when is_list(Config) -> file:delete(Filename), ok. +deterministic(doc) -> + "Check yecc respects the +deterministic flag."; +deterministic(suite) -> []; +deterministic(Config) when is_list(Config) -> + Dir = ?privdir, + Filename = filename:join(Dir, "file.yrl"), + Parserfile = filename:join(Dir, "file.erl"), + ok = file:write_file(Filename, + <<"Nonterminals nt. + Terminals t. + Rootsymbol nt. + nt -> t.">>), + + %% Generated yecc parsers need to include the yeccpre.hrl + %% header file, so we'll get a -file attribute corresponding + %% to that include. In deterministic mode, that include should + %% only use the basename, "yeccpre.hrl", but otherwise, it should + %% contain the full path. + + %% Matches when OTP is not installed (e.g. /lib/parsetools/include/yeccpre.hrl) + %% and when it is (e.g. /lib/parsetools-2.3.2/include/yeccpre.hrl) + AbsolutePathSuffix = "/lib/parsetools.*/include/yeccpre\.hrl", + + ok = yecc:compile(Filename, Parserfile, #options{specific=[deterministic]}), + {ok, FormsDet} = epp:parse_file(Parserfile,[]), + ?assertMatch(false, search_for_file_attr(AbsolutePathSuffix, FormsDet)), + ?assertMatch({value, _}, search_for_file_attr("yeccpre\.hrl", FormsDet)), + file:delete(Parserfile), + + ok = yecc:compile(Filename, Parserfile, #options{}), + {ok, Forms} = epp:parse_file(Parserfile,[]), + ?assertMatch({value, _}, search_for_file_attr(AbsolutePathSuffix, Forms)), + file:delete(Parserfile), + + file:delete(Filename), + ok. + empty(doc) -> "'$empty'."; empty(suite) -> []; @@ -2284,3 +2322,13 @@ process_list() -> safe_second_element({_,Info}) -> Info; safe_second_element(Other) -> Other. + +search_for_file_attr(PartialFilePathRegex, Forms) -> + lists:search(fun + ({attribute, _, file, {FileAttr, _}}) -> + case re:run(FileAttr, PartialFilePathRegex) of + nomatch -> false; + _ -> true + end; + (_) -> false end, + Forms). diff --git a/lib/public_key/asn1/Makefile b/lib/public_key/asn1/Makefile index d33e13fb14..c1adf58ed4 100644 --- a/lib/public_key/asn1/Makefile +++ b/lib/public_key/asn1/Makefile @@ -70,6 +70,10 @@ ERL_COMPILE_FLAGS += $(EXTRA_ERLC_FLAGS) ASN_FLAGS = -bber +der +noobj +asn1config +ifeq ($(ERL_DETERMINISTIC),yes) + ASN_FLAGS += +deterministic +endif + # ---------------------------------------------------- # Targets # ---------------------------------------------------- diff --git a/lib/public_key/test/Makefile b/lib/public_key/test/Makefile index 6c39c534d2..aa42cf281f 100644 --- a/lib/public_key/test/Makefile +++ b/lib/public_key/test/Makefile @@ -55,6 +55,7 @@ RELSYSDIR = $(RELEASE_PATH)/public_key_test # FLAGS # ---------------------------------------------------- ERL_COMPILE_FLAGS += $(INCLUDES) +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) EBIN = . diff --git a/lib/reltool/test/Makefile b/lib/reltool/test/Makefile index 789019cf7d..245c9c9f00 100644 --- a/lib/reltool/test/Makefile +++ b/lib/reltool/test/Makefile @@ -51,6 +51,7 @@ RELSYSDIR = $(RELEASE_PATH)/reltool_test # FLAGS # ---------------------------------------------------- ERL_COMPILE_FLAGS += -pa $(ERL_TOP)/lib/reltool/ebin/ +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) EBIN = . diff --git a/lib/runtime_tools/test/Makefile b/lib/runtime_tools/test/Makefile index f899d53f7f..c9578d376e 100644 --- a/lib/runtime_tools/test/Makefile +++ b/lib/runtime_tools/test/Makefile @@ -31,6 +31,7 @@ RELSYSDIR = $(RELEASE_PATH)/runtime_tools_test ERL_MAKE_FLAGS += ERL_COMPILE_FLAGS += -Werror +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) EBIN = . diff --git a/lib/sasl/test/Makefile b/lib/sasl/test/Makefile index 11c2a9e69f..adc5a927ac 100644 --- a/lib/sasl/test/Makefile +++ b/lib/sasl/test/Makefile @@ -58,6 +58,7 @@ RELSYSDIR = $(RELEASE_PATH)/sasl_test # ---------------------------------------------------- ERL_MAKE_FLAGS += ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/sasl/src +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) EBIN = . diff --git a/lib/snmp/src/compile/Makefile b/lib/snmp/src/compile/Makefile index d37eaf9636..f255237a04 100644 --- a/lib/snmp/src/compile/Makefile +++ b/lib/snmp/src/compile/Makefile @@ -85,6 +85,10 @@ ERL_COMPILE_FLAGS += -I../../include \ YRL_FLAGS = -o . +ifeq ($(ERL_DETERMINISTIC),yes) + YRL_FLAGS += +deterministic +endif + # ---------------------------------------------------- # Targets diff --git a/lib/snmp/test/Makefile b/lib/snmp/test/Makefile index ac25a0d0b3..8de1b1e80d 100644 --- a/lib/snmp/test/Makefile +++ b/lib/snmp/test/Makefile @@ -161,6 +161,7 @@ ERL_COMPILE_FLAGS += -I../../snmp/src/app \ +'{parse_transform,sys_pre_attributes}' \ +'{attribute,insert,app_vsn,$(APP_VSN)}' \ $(SNMP_FLAGS) +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) ERL_SNMP_FLAGS = $(SNMP_MIB_FLAGS) \ -I../priv/mibs diff --git a/lib/ssh/test/Makefile b/lib/ssh/test/Makefile index e07806f488..908312f8de 100644 --- a/lib/ssh/test/Makefile +++ b/lib/ssh/test/Makefile @@ -98,6 +98,7 @@ RELSYSDIR = $(RELEASE_PATH)/ssh_test INCLUDES = -I$(ERL_TOP)/lib/ssh/src ERL_COMPILE_FLAGS += $(INCLUDES) -pa ../ebin +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) EBIN = . diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile index 5a69aeb674..ac1318bd14 100644 --- a/lib/ssl/test/Makefile +++ b/lib/ssl/test/Makefile @@ -144,6 +144,7 @@ RELSYSDIR = $(RELEASE_PATH)/ssl_test # running the target "targets". # ---------------------------------------------------- ERL_COMPILE_FLAGS += $(INCLUDES) +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) # ---------------------------------------------------- # Targets diff --git a/lib/stdlib/doc/src/epp.xml b/lib/stdlib/doc/src/epp.xml index 6cd715c55c..c2c24ee34d 100644 --- a/lib/stdlib/doc/src/epp.xml +++ b/lib/stdlib/doc/src/epp.xml @@ -131,6 +131,10 @@ attributes inserted during preprocessing, you can do with <c>{source_name, <anno>SourceName</anno>}</c>. If unset it will default to the name of the opened file.</p> + <p>Setting <c>{deterministic, <anno>Enabled</anno>}</c> will + additionally reduce the file name of the implicit -file() + attributes inserted during preprocessing to only the basename + of the path.</p> <p>If <c>extra</c> is specified in <c><anno>Options</anno></c>, the return value is <c>{ok, <anno>Epp</anno>, <anno>Extra</anno>}</c> instead diff --git a/lib/stdlib/src/Makefile b/lib/stdlib/src/Makefile index 369a448fe5..761d6c4c28 100644 --- a/lib/stdlib/src/Makefile +++ b/lib/stdlib/src/Makefile @@ -166,6 +166,12 @@ endif ERL_COMPILE_FLAGS += -Werror ERL_COMPILE_FLAGS += -I../include -I../../kernel/include +ifeq ($(ERL_DETERMINISTIC),yes) + DETERMINISM_FLAG = +deterministic +else + DETERMINISM_FLAG = +endif + # ---------------------------------------------------- # Targets # ---------------------------------------------------- @@ -192,16 +198,17 @@ primary_bootstrap_compiler: \ $(BOOTSTRAP_COMPILER)/ebin/io.beam \ $(BOOTSTRAP_COMPILER)/ebin/otp_internal.beam + $(BOOTSTRAP_COMPILER)/ebin/erl_parse.beam: erl_parse.yrl $(gen_verbose) - $(V_at)$(ERLC) -o $(BOOTSTRAP_COMPILER)/egen erl_parse.yrl - $(V_at)$(ERLC) -o $(BOOTSTRAP_COMPILER)/ebin $(BOOTSTRAP_COMPILER)/egen/erl_parse.erl + $(V_at)$(ERLC) -o $(BOOTSTRAP_COMPILER)/egen $(DETERMINISM_FLAG) erl_parse.yrl + $(V_at)$(ERLC) -o $(BOOTSTRAP_COMPILER)/ebin $(DETERMINISM_FLAG) $(BOOTSTRAP_COMPILER)/egen/erl_parse.erl $(BOOTSTRAP_TOP)/lib/stdlib/egen/erl_parse.erl: erl_parse.yrl $(yecc_verbose)$(ERLC) $(YRL_FLAGS) -o$(BOOTSTRAP_TOP)/lib/stdlib/egen erl_parse.yrl $(BOOTSTRAP_COMPILER)/ebin/%.beam: %.erl - $(V_ERLC) -o $(BOOTSTRAP_COMPILER)/ebin $< + $(V_ERLC) -o $(BOOTSTRAP_COMPILER)/ebin $(DETERMINISM_FLAG) $< # ---------------------------------------------------- # Special Build Targets diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl index 4d0dde0f52..bdb0bc64a2 100644 --- a/lib/stdlib/src/epp.erl +++ b/lib/stdlib/src/epp.erl @@ -77,7 +77,8 @@ erl_scan_opts = [] :: [_], features = [] :: [atom()], else_reserved = false :: boolean(), - fname = [] :: function_name_type() + fname = [] :: function_name_type(), + deterministic = false :: boolean() }). %% open(Options) @@ -119,6 +120,7 @@ open(Name, Path, Pdm) -> Options :: [{'default_encoding', DefEncoding :: source_encoding()} | {'includes', IncludePath :: [DirectoryName :: file:name()]} | {'source_name', SourceName :: file:name()} | + {'deterministic', Enabled :: boolean()} | {'macros', PredefMacros :: macros()} | {'name',FileName :: file:name()} | {'location',StartLocation :: erl_anno:location()} | @@ -623,6 +625,7 @@ init_server(Pid, FileName, Options, St0) -> %% the default location is 1 for backwards compatibility, not {1,1} AtLocation = proplists:get_value(location, Options, 1), + Deterministic = proplists:get_value(deterministic, Options, false), St = St0#epp{delta=0, name=SourceName, name2=SourceName, path=Path, location=AtLocation, macs=Ms1, default_encoding=DefEncoding, @@ -630,11 +633,12 @@ init_server(Pid, FileName, Options, St0) -> [{text_fun, keep_ftr_keywords()}, {reserved_word_fun, ResWordFun}], features = Features, - else_reserved = ResWordFun('else')}, + else_reserved = ResWordFun('else'), + deterministic = Deterministic}, From = wait_request(St), Anno = erl_anno:new(AtLocation), enter_file_reply(From, file_name(SourceName), Anno, - AtLocation, code), + AtLocation, code, Deterministic), wait_req_scan(St); {error,E} -> epp_reply(Pid, {error,E}) @@ -798,14 +802,15 @@ enter_file(NewName, Inc, From, St) -> enter_file2(NewF, Pname, From, St0, AtLocation) -> Anno = erl_anno:new(AtLocation), - enter_file_reply(From, Pname, Anno, AtLocation, code), + enter_file_reply(From, Pname, Anno, AtLocation, code, St0#epp.deterministic), #epp{macs = Ms0, default_encoding = DefEncoding, in_prefix = InPrefix, erl_scan_opts = ScanOpts, else_reserved = ElseReserved, - features = Ftrs} = St0, - Ms = Ms0#{'FILE':={none,[{string,Anno,Pname}]}}, + features = Ftrs, + deterministic = Deterministic} = St0, + Ms = Ms0#{'FILE':={none,[{string,Anno,source_name(St0,Pname)}]}}, %% update the head of the include path to be the directory of the new %% source file, so that an included file can always include other files %% relative to its current location (this is also how C does it); note @@ -820,16 +825,17 @@ enter_file2(NewF, Pname, From, St0, AtLocation) -> features = Ftrs, erl_scan_opts = ScanOpts, else_reserved = ElseReserved, - default_encoding=DefEncoding}. + default_encoding=DefEncoding, + deterministic=Deterministic}. -enter_file_reply(From, Name, LocationAnno, AtLocation, Where) -> +enter_file_reply(From, Name, LocationAnno, AtLocation, Where, Deterministic) -> Anno0 = erl_anno:new(AtLocation), Anno = case Where of code -> Anno0; generated -> erl_anno:set_generated(true, Anno0) end, Rep = {ok, [{'-',Anno},{atom,Anno,file},{'(',Anno}, - {string,Anno,Name},{',',Anno}, + {string,Anno,source_name(Deterministic,Name)},{',',Anno}, {integer,Anno,get_line(LocationAnno)},{')',LocationAnno}, {dot,Anno}]}, epp_reply(From, Rep). @@ -865,13 +871,13 @@ leave_file(From, St) -> Ftrs = St#epp.features, ElseReserved = St#epp.else_reserved, ScanOpts = St#epp.erl_scan_opts, - Ms = Ms0#{'FILE':={none,[{string,Anno,OldName2}]}}, + Ms = Ms0#{'FILE':={none,[{string,Anno,source_name(St,OldName2)}]}}, NextSt = OldSt#epp{sstk=Sts,macs=Ms,uses=St#epp.uses, in_prefix = InPrefix, features = Ftrs, else_reserved = ElseReserved, erl_scan_opts = ScanOpts}, - enter_file_reply(From, OldName, Anno, CurrLoc, code), + enter_file_reply(From, OldName, Anno, CurrLoc, code, St#epp.deterministic), case OldName2 =:= OldName of true -> ok; @@ -879,7 +885,7 @@ leave_file(From, St) -> NFrom = wait_request(NextSt), OldAnno = erl_anno:new(OldLoc), enter_file_reply(NFrom, OldName2, OldAnno, - CurrLoc, generated) + CurrLoc, generated, St#epp.deterministic) end, wait_req_scan(NextSt); [] -> @@ -1463,9 +1469,9 @@ scan_file(Tokens0, Tf, From, St) -> scan_file1([{'(',_Alp},{string,_As,Name},{',',_Ac},{integer,_Ai,Ln},{')',_Arp}, {dot,_Ad}], Tf, From, St) -> Anno = erl_anno:new(Ln), - enter_file_reply(From, Name, Anno, loc(Tf), generated), + enter_file_reply(From, Name, Anno, loc(Tf), generated, St#epp.deterministic), Ms0 = St#epp.macs, - Ms = Ms0#{'FILE':={none,[{string,line1(),Name}]}}, + Ms = Ms0#{'FILE':={none,[{string,line1(),source_name(St,Name)}]}}, Locf = loc(Tf), NewLoc = new_location(Ln, St#epp.location, Locf), Delta = get_line(element(2, Tf))-Ln + St#epp.delta, @@ -2084,3 +2090,12 @@ interpret_file_attr([Form0 | Forms], Delta, Fs) -> [Form | interpret_file_attr(Forms, Delta, Fs)]; interpret_file_attr([], _Delta, _Fs) -> []. + +-spec source_name(#epp{} | boolean(), file:filename_all()) -> file:filename_all(). +source_name(Deterministic, Name) when is_boolean(Deterministic) -> + case Deterministic of + true -> filename:basename(Name); + false -> Name + end; +source_name(St, Name) -> + source_name(St#epp.deterministic, Name). diff --git a/lib/stdlib/test/Makefile b/lib/stdlib/test/Makefile index f030235046..b8e4d89996 100644 --- a/lib/stdlib/test/Makefile +++ b/lib/stdlib/test/Makefile @@ -122,6 +122,7 @@ RELSYSDIR = $(RELEASE_PATH)/stdlib_test ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/kernel/include \ -I$(ERL_TOP)/lib/stdlib/include +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) EBIN = . diff --git a/lib/stdlib/test/epp_SUITE.erl b/lib/stdlib/test/epp_SUITE.erl index 5d7e362c50..c62f6fa3c1 100644 --- a/lib/stdlib/test/epp_SUITE.erl +++ b/lib/stdlib/test/epp_SUITE.erl @@ -29,7 +29,8 @@ otp_8562/1, otp_8665/1, otp_8911/1, otp_10302/1, otp_10820/1, otp_11728/1, encoding/1, extends/1, function_macro/1, test_error/1, test_warning/1, otp_14285/1, - test_if/1,source_name/1,otp_16978/1,otp_16824/1,scan_file/1,file_macro/1]). + test_if/1,source_name/1,otp_16978/1,otp_16824/1,scan_file/1,file_macro/1, + deterministic_include/1, nondeterministic_include/1]). -export([epp_parse_erl_form/2]). @@ -50,6 +51,7 @@ config(data_dir, _) -> filename:absname("./epp_SUITE_data"). -else. -include_lib("common_test/include/ct.hrl"). +-include_lib("stdlib/include/assert.hrl"). -export([init_per_testcase/2, end_per_testcase/2]). init_per_testcase(_, Config) -> @@ -70,7 +72,8 @@ all() -> overload_mac, otp_8388, otp_8470, otp_8562, otp_8665, otp_8911, otp_10302, otp_10820, otp_11728, encoding, extends, function_macro, test_error, test_warning, - otp_14285, test_if, source_name, otp_16978, otp_16824, scan_file, file_macro]. + otp_14285, test_if, source_name, otp_16978, otp_16824, scan_file, file_macro, + deterministic_include, nondeterministic_include]. groups() -> [{upcase_mac, [], [upcase_mac_1, upcase_mac_2]}, @@ -124,6 +127,64 @@ file_macro(Config) when is_list(Config) -> "Other source" = FileA = FileB, ok. +deterministic_include(Config) when is_list(Config) -> + DataDir = proplists:get_value(data_dir, Config), + File = filename:join(DataDir, "deterministic_include.erl"), + {ok, List} = epp:parse_file(File, [{includes, [DataDir]}, + {deterministic, true}, + {source_name, "deterministic_include.erl"}]), + + %% In deterministic mode, only basenames, rather than full paths, should + %% be written to the -file() attributes resulting from -include and -include_lib + ?assert(lists:any(fun + ({attribute,_Anno,file,{"baz.hrl",_Line}}) -> true; + (_) -> false + end, + List), + "Expected a basename in the -file attribute resulting from " ++ + "including baz.hrl in deterministic mode."), + ?assert(lists:any(fun + ({attribute,_Anno,file,{"file.hrl",_Line}}) -> true; + (_) -> false + end, + List), + "Expected a basename in the -file attribute resulting from " ++ + "including file.hrl in deterministic mode."), + ok. + +nondeterministic_include(Config) when is_list(Config) -> + DataDir = proplists:get_value(data_dir, Config), + File = filename:join(DataDir, "deterministic_include.erl"), + {ok, List} = epp:parse_file(File, [{includes, [DataDir]}, + {source_name, "deterministic_include.erl"}]), + + %% Outside of deterministic mode, full paths, should be written to + %% the -file() attributes resulting from -include and -include_lib + %% to make debugging easier. + %% We don't try to assume what the full absolute path will be in the + %% unit test, since that can depend on the environment and how the + %% test is executed. Instead, we just look for whether there is + %% the parent directory along with the basename at least. + IncludeAbsolutePathSuffix = filename:join("include","baz.hrl"), + ?assert(lists:any(fun + ({attribute,_Anno,file,{IncludePath,_Line}}) -> + lists:suffix(IncludeAbsolutePathSuffix,IncludePath); + (_) -> false + end, + List), + "Expected an absolute in the -file attribute resulting from " ++ + "including baz.hrl outside of deterministic mode."), + IncludeLibAbsolutePathSuffix = filename:join("include","file.hrl"), + ?assert(lists:any(fun + ({attribute,_Anno,file,{IncludePath,_line}}) -> + lists:suffix(IncludeLibAbsolutePathSuffix,IncludePath); + (_) -> false + end, + List), + "Expected an absolute in the -file attribute resulting from " ++ + "including file.hrl outside of deterministic mode."), + ok. + %%% Here is a little reimplementation of epp:parse_file, which times out %%% after 4 seconds if the epp server doesn't respond. If we use the %%% regular epp:parse_file, the test case will time out, and then epp diff --git a/lib/stdlib/test/epp_SUITE_data/deterministic_include.erl b/lib/stdlib/test/epp_SUITE_data/deterministic_include.erl new file mode 100644 index 0000000000..67763b29a0 --- /dev/null +++ b/lib/stdlib/test/epp_SUITE_data/deterministic_include.erl @@ -0,0 +1,6 @@ +-module(deterministic_include). + +-export([]). + +-include("include/baz.hrl"). +-include_lib("kernel/include/file.hrl"). diff --git a/lib/stdlib/test/epp_SUITE_data/include/baz.hrl b/lib/stdlib/test/epp_SUITE_data/include/baz.hrl new file mode 100644 index 0000000000..c0ef7a6e51 --- /dev/null +++ b/lib/stdlib/test/epp_SUITE_data/include/baz.hrl @@ -0,0 +1 @@ +-define(BAZ, true). diff --git a/lib/syntax_tools/test/Makefile b/lib/syntax_tools/test/Makefile index 51fe2417b1..deee5ab814 100644 --- a/lib/syntax_tools/test/Makefile +++ b/lib/syntax_tools/test/Makefile @@ -27,6 +27,7 @@ RELSYSDIR = $(RELEASE_PATH)/syntax_tools_test ERL_MAKE_FLAGS += ERL_COMPILE_FLAGS += +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) EBIN = . diff --git a/lib/tftp/test/Makefile b/lib/tftp/test/Makefile index 3eb0886f66..a3caf45321 100644 --- a/lib/tftp/test/Makefile +++ b/lib/tftp/test/Makefile @@ -152,6 +152,7 @@ RELTESTSYSBINDIR = $(RELTESTSYSALLDATADIR)/bin ERL_COMPILE_FLAGS += \ $(INCLUDES) \ $(TFTP_FLAGS) +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) # ---------------------------------------------------- # Targets diff --git a/lib/tools/test/Makefile b/lib/tools/test/Makefile index 571fdd07e9..984568e4c5 100644 --- a/lib/tools/test/Makefile +++ b/lib/tools/test/Makefile @@ -54,6 +54,7 @@ RELSYSDIR = $(RELEASE_PATH)/tools_test # ---------------------------------------------------- ERL_MAKE_FLAGS += ERL_COMPILE_FLAGS += +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) EBIN = . diff --git a/lib/xmerl/src/Makefile b/lib/xmerl/src/Makefile index 0a9f8391c7..e7e7c8e978 100644 --- a/lib/xmerl/src/Makefile +++ b/lib/xmerl/src/Makefile @@ -127,6 +127,11 @@ ERL_COMPILE_FLAGS += \ # +bin_opt_info +ifeq ($(ERL_DETERMINISTIC),yes) + DETERMINISM_FLAG = +deterministic +else + DETERMINISM_FLAG = +endif # ---------------------------------------------------- # Targets @@ -173,10 +178,10 @@ $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@ xmerl_xpath_parse.erl: xmerl_xpath_parse.yrl - $(yecc_verbose)$(ERLC) -o $(ESRC) $< + $(yecc_verbose)$(ERLC) -o $(ESRC) $(DETERMINISM_FLAG) $< xmerl_b64Bin.erl: xmerl_b64Bin.yrl - $(yecc_verbose)$(ERLC) -o $(ESRC) $< + $(yecc_verbose)$(ERLC) -o $(ESRC) $(DETERMINISM_FLAG) $< xmerl_sax_parser_list.erl: xmerl_sax_parser_list.erlsrc xmerl_sax_parser_base.erlsrc $(gen_verbose)cat xmerl_sax_parser_list.erlsrc xmerl_sax_parser_base.erlsrc >$@ diff --git a/lib/xmerl/test/Makefile b/lib/xmerl/test/Makefile index 49091a9a54..97180d8051 100644 --- a/lib/xmerl/test/Makefile +++ b/lib/xmerl/test/Makefile @@ -86,6 +86,7 @@ RELSYSDIR = $(RELEASE_PATH)/xmerl_test # ---------------------------------------------------- ERL_COMPILE_FLAGS += +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) # ---------------------------------------------------- diff --git a/make/otp.mk.in b/make/otp.mk.in index 7ec4aea91a..61654ad5cb 100644 --- a/make/otp.mk.in +++ b/make/otp.mk.in @@ -92,6 +92,8 @@ BITS64 = @BITS64@ OTP_RELEASE = @OTP_RELEASE@ +ERL_DETERMINISTIC = @ERL_DETERMINISTIC@ + # ---------------------------------------------------- # Erlang language section # ---------------------------------------------------- @@ -104,6 +106,11 @@ ifdef BOOTSTRAP else ERL_COMPILE_FLAGS += +debug_info endif +ifeq ($(ERL_DETERMINISTIC),yes) + ERL_COMPILE_FLAGS += +deterministic + YRL_FLAGS += +deterministic + XRL_FLAGS += +deterministic +endif ERLC_WFLAGS = -W ERLC = erlc $(ERLC_WFLAGS) $(ERLC_FLAGS) |