diff options
author | Henrik Nord <[email protected]> | 2011-09-13 12:02:19 +0200 |
---|---|---|
committer | Henrik Nord <[email protected]> | 2011-09-13 12:02:23 +0200 |
commit | e9e118a25ee822e4568d785844d249e083cd88cf (patch) | |
tree | 636bddf9f6d41aefdf36cd6821560df4a66d249b | |
parent | a40655461a03f6b075a1140810f020f5b2bf35b1 (diff) | |
parent | bbdc6a3c0fac080af7b60e6cf7d9732532027939 (diff) | |
download | otp-e9e118a25ee822e4568d785844d249e083cd88cf.tar.gz otp-e9e118a25ee822e4568d785844d249e083cd88cf.tar.bz2 otp-e9e118a25ee822e4568d785844d249e083cd88cf.zip |
Merge branch 'ta/werror' into dev
* ta/werror:
snmp: extend warnings_as_errors test
systools: add warnings_as_errors option
asn1ct: add warnings_as_errors option
leex: optimize werror/1
yecc: optimize werror/1
yecc: use more descriptive name: 'werror'
leex: use more descriptive name: 'werror'
compile: optimize werror/1
compile: log warnings as errors if -Werror is enabled
yecc: log warnings as errors if -Werror is enabled
leex: log warnings as errors if -Werror is enabled
yecc: honour -Werror passed from erlc
leex: honour -Werror passed from erlc
Do not write beam file if Werr and warnings /= []
parsetools: test if warnings_as_errors writes file
OTP-9536
-rw-r--r-- | erts/test/erlc_SUITE.erl | 2 | ||||
-rw-r--r-- | lib/asn1/doc/src/asn1ct.xml | 6 | ||||
-rw-r--r-- | lib/asn1/src/asn1ct.erl | 29 | ||||
-rw-r--r-- | lib/asn1/src/asn1ct_check.erl | 50 | ||||
-rw-r--r-- | lib/asn1/test/asn1_SUITE.erl.src | 4 | ||||
-rw-r--r-- | lib/asn1/test/test_compile_options.erl | 39 | ||||
-rw-r--r-- | lib/compiler/src/compile.erl | 50 | ||||
-rw-r--r-- | lib/compiler/test/error_SUITE.erl | 65 | ||||
-rw-r--r-- | lib/parsetools/src/leex.erl | 52 | ||||
-rw-r--r-- | lib/parsetools/src/yecc.erl | 37 | ||||
-rw-r--r-- | lib/parsetools/test/leex_SUITE.erl | 11 | ||||
-rw-r--r-- | lib/parsetools/test/yecc_SUITE.erl | 10 | ||||
-rw-r--r-- | lib/sasl/doc/src/systools.xml | 10 | ||||
-rw-r--r-- | lib/sasl/src/systools_lib.erl | 7 | ||||
-rw-r--r-- | lib/sasl/src/systools_make.erl | 174 | ||||
-rw-r--r-- | lib/sasl/src/systools_relup.erl | 68 | ||||
-rw-r--r-- | lib/sasl/test/systools_SUITE.erl | 41 | ||||
-rw-r--r-- | lib/snmp/test/snmp_compiler_test.erl | 9 |
18 files changed, 472 insertions, 192 deletions
diff --git a/erts/test/erlc_SUITE.erl b/erts/test/erlc_SUITE.erl index 2b5cb11f02..a9e28672e3 100644 --- a/erts/test/erlc_SUITE.erl +++ b/erts/test/erlc_SUITE.erl @@ -79,7 +79,7 @@ compile_erl(Config) when is_list(Config) -> ?line run(Config, Cmd, FileName, "-Werror", ["compile: warnings being treated as errors\$", - "Warning: function foo/0 is unused\$", + "function foo/0 is unused\$", "_ERROR_"]), %% Check a bad file. diff --git a/lib/asn1/doc/src/asn1ct.xml b/lib/asn1/doc/src/asn1ct.xml index 265f8735c2..50458b4a9a 100644 --- a/lib/asn1/doc/src/asn1ct.xml +++ b/lib/asn1/doc/src/asn1ct.xml @@ -53,7 +53,7 @@ <v>Option = ber_bin | per_bin | uper_bin | der | compact_bit_string | noobj | {n2n,EnumTypeName} |{outdir,Dir} | {i,IncludeDir} | optimize | driver | asn1config | undec_rest | {inline,OutputName} | inline | - {macro_name_prefix, Prefix} | {record_name_prefix, Prefix} | verbose</v> + {macro_name_prefix, Prefix} | {record_name_prefix, Prefix} | verbose | warnings_as_errors</v> <v>OldOption = ber | per</v> <v>Reason = term()</v> <v>Prefix = string()</v> @@ -289,6 +289,10 @@ Binary = binary() <p>Causes more verbose information from the compiler describing what it is doing.</p> </item> + <tag><c>warnings_as_errors</c></tag> + <item> + <p>Causes warnings to be treated as errors.</p> + </item> </taglist> <p>Any additional option that is applied will be passed to the final step when the generated .erl file is compiled. diff --git a/lib/asn1/src/asn1ct.erl b/lib/asn1/src/asn1ct.erl index a167d27f82..e26fadd160 100644 --- a/lib/asn1/src/asn1ct.erl +++ b/lib/asn1/src/asn1ct.erl @@ -39,7 +39,7 @@ add_tobe_refed_func/1,add_generated_refed_func/1, maybe_rename_function/3,latest_sindex/0,current_sindex/0, set_current_sindex/1,next_sindex/0,maybe_saved_sindex/2, - parse_and_save/2,verbose/3,warning/3,error/3]). + parse_and_save/2,verbose/3,warning/3,warning/4,error/3]). -include("asn1_records.hrl"). -include_lib("stdlib/include/erl_compile.hrl"). @@ -825,10 +825,13 @@ generate({true,{M,_Module,GenTOrV}},OutFile,EncodingRule,Options) -> case catch specialized_decode_prepare(EncodingRule,M,GenTOrV,Options) of {error, enoent} -> ok; {error, Reason} -> warning("Error in configuration " - "file: ~n~p~n",[Reason],Options); + "file: ~n~p~n",[Reason],Options, + "Error in configuration file"); {'EXIT',Reason} -> warning("Internal error when " "analyzing configuration " - "file: ~n~p~n",[Reason],Options); + "file: ~n~p~n",[Reason],Options, + "Internal error when " + "analyzing configuration"); _ -> ok end, @@ -2524,14 +2527,14 @@ type_check(#'Externaltypereference'{}) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Report functions. %% -%% Errors messages are controlled with the 'errors' compiler option +%% Error messages are controlled with the 'errors' compiler option %% Warning messages are controlled with the 'warnings' compiler option %% Verbose messages are controlled with the 'verbose' compiler option error(Format, Args, S) -> case is_error(S) of true -> - io:format("Error: " ++ Format, Args); + io:format(Format, Args); false -> ok end. @@ -2544,6 +2547,17 @@ warning(Format, Args, S) -> ok end. +warning(Format, Args, S, Reason) -> + case {is_werr(S), is_error(S), is_warning(S)} of + {true, true, _} -> + io:format(Format, Args), + throw({error, Reason}); + {false, _, true} -> + io:format(Format, Args); + _ -> + ok + end. + verbose(Format, Args, S) -> case is_verbose(S) of true -> @@ -2566,3 +2580,8 @@ is_verbose(S) when is_record(S, state) -> is_verbose(S#state.options); is_verbose(O) -> lists:member(verbose, O). + +is_werr(S) when is_record(S, state) -> + is_werr(S#state.options); +is_werr(O) -> + lists:member(warnings_as_errors, O). diff --git a/lib/asn1/src/asn1ct_check.erl b/lib/asn1/src/asn1ct_check.erl index efd731f052..e318477234 100644 --- a/lib/asn1/src/asn1ct_check.erl +++ b/lib/asn1/src/asn1ct_check.erl @@ -2031,7 +2031,7 @@ get_objectset_def2(_S,T = #typedef{typespec=#'ObjectSet'{}},_CField) -> T; get_objectset_def2(S,T,_CField) -> asn1ct:warning("get_objectset_def2: uncontrolled object set structure:~n~p~n", - [T],S). + [T],S,"get_objectset_def2: uncontrolled object set structure"). type_name(S,#type{def=Def}) -> CurrMod = S#state.mname, @@ -2705,7 +2705,7 @@ normalize_value(S,Type,{'DEFAULT',Value},NameList) -> normalize_objectclassfieldvalue(S,Value,NL); Err -> asn1ct:warning("could not check default value ~p~nType:~n~p~nNameList:~n~p~n", - [Value,Type,Err],S), + [Value,Type,Err],S,"could not check default value"), Value end; normalize_value(S,Type,Val,NameList) -> @@ -2791,22 +2791,27 @@ normalize_bitstring(S,Value,Type)-> case catch lists:map(F,RecList) of {error,Reason} -> asn1ct:warning("default value not " - "compatible with type definition ~p~n", - [Reason],S), + "compatible with type definition ~p~n", + [Reason],S, + "default value not " + "compatible with type definition"), Value; NewList -> NewList end; _ -> asn1ct:warning("default value not " - "compatible with type definition ~p~n", - [RecList],S), + "compatible with type definition ~p~n", + [RecList],S, + "default value not " + "compatible with type definition"), Value end; {Name,String} when is_atom(Name) -> normalize_bitstring(S,String,Type); Other -> - asn1ct:warning("illegal default value ~p~n",[Other],S), + asn1ct:warning("illegal default value ~p~n",[Other],S, + "illegal default value"), Value end. @@ -2846,12 +2851,14 @@ normalize_octetstring(S,Value,CType) -> lists:map(fun([])-> ok; (H)when H > 255-> asn1ct:warning("not legal octet value ~p in OCTET STRING, ~p~n", - [H,List],S); + [H,List],S, + "not legal octet value ~p in OCTET STRING"); (_)-> ok end, List), List; Other -> - asn1ct:warning("unknown default value ~p~n",[Other],S), + asn1ct:warning("unknown default value ~p~n",[Other],S, + "unknown default value"), Value end. @@ -2908,13 +2915,15 @@ normalize_enumerated(S,{Name,EnumV},CType) when is_atom(Name) -> normalize_enumerated(S,Value,{CType1,CType2}) when is_list(CType1), is_list(CType2)-> normalize_enumerated(S,Value,CType1++CType2); normalize_enumerated(S,V,CType) -> - asn1ct:warning("Enumerated unknown type ~p~n",[CType],S), + asn1ct:warning("Enumerated unknown type ~p~n",[CType],S, + "Enumerated unknown type"), V. normalize_enumerated2(S,V,Enum) -> case lists:keysearch(V,1,Enum) of {value,{Val,_}} -> Val; _ -> - asn1ct:warning("Enumerated value is not correct ~p~n",[V],S), + asn1ct:warning("enumerated value is not correct ~p~n",[V],S, + "enumerated value is not correct"), V end. @@ -2925,7 +2934,8 @@ normalize_choice(S,{'CHOICE',{C,V}},CType,NameList) when is_atom(C) -> {C,normalize_value(S,CT,{'DEFAULT',V}, [Name|NameList])}; Other -> - asn1ct:warning("Wrong format of type/value ~p/~p~n",[Other,V],S), + asn1ct:warning("Wrong format of type/value ~p/~p~n",[Other,V],S, + "Wrong format of type/value"), {C,V} end; normalize_choice(S,{'DEFAULT',ValueList},CType,NameList) when is_list(ValueList) -> @@ -3101,7 +3111,8 @@ normalize_s_of(SorS,S,Value,Type,NameList) when is_list(Value) -> List when is_list(List) -> List; _ -> - asn1ct:warning("~p could not handle value ~p~n",[SorS,Value],S), + asn1ct:warning("~p could not handle value ~p~n",[SorS,Value],S, + "could not handle value"), Value end; normalize_s_of(SorS,S,Value,Type,NameList) @@ -3159,7 +3170,8 @@ get_normalized_value(S,Val,Type,Func,AddArg) -> V2 = sort_val_if_set(AddArg,NewVal,Type), call_Func(update_state(S,ExtM),V2,Type,Func,AddArg); _ -> - asn1ct:warning("default value not comparable ~p~n",[Val],S), + asn1ct:warning("default value not comparable ~p~n",[Val],S, + "default value not comparable"), Val end. @@ -5756,7 +5768,8 @@ ascending_order_check1(S,TypeName, [C1 = #'ComponentType'{tags=[{_,T}|_]}, C2 = #'ComponentType'{tags=[{_,T}|_]}|Rest]) -> asn1ct:warning("Indistinct tag ~p in SET ~p, components ~p and ~p~n", - [T,TypeName,C1#'ComponentType'.name,C2#'ComponentType'.name],S), + [T,TypeName,C1#'ComponentType'.name,C2#'ComponentType'.name],S, + "Indistinct tag in SET"), ascending_order_check1(S,TypeName,[C2|Rest]); ascending_order_check1(S,TypeName, [C1 = #'ComponentType'{tags=[{'UNIVERSAL',T1}|_]}, @@ -5764,9 +5777,10 @@ ascending_order_check1(S,TypeName, case (decode_type(T1) == decode_type(T2)) of true -> asn1ct:warning("Indistinct tags ~p and ~p in" - " SET ~p, components ~p and ~p~n", - [T1,T2,TypeName,C1#'ComponentType'.name, - C2#'ComponentType'.name],S), + " SET ~p, components ~p and ~p~n", + [T1,T2,TypeName,C1#'ComponentType'.name, + C2#'ComponentType'.name],S, + "Indistinct tags and in SET"), ascending_order_check1(S,TypeName,[C2|Rest]); _ -> ascending_order_check1(S,TypeName,[C2|Rest]) diff --git a/lib/asn1/test/asn1_SUITE.erl.src b/lib/asn1/test/asn1_SUITE.erl.src index 582ccd877c..e7f93a4053 100644 --- a/lib/asn1/test/asn1_SUITE.erl.src +++ b/lib/asn1/test/asn1_SUITE.erl.src @@ -2236,8 +2236,10 @@ test_compile_options(Config) -> ?line ok = test_compile_options:path(Config), ?line ok = test_compile_options:noobj(Config), ?line ok = test_compile_options:record_name_prefix(Config), - ?line ok = test_compile_options:verbose(Config) + ?line ok = test_compile_options:verbose(Config), + ?line ok = test_compile_options:warnings_as_errors(Config) end. + testDoubleEllipses(suite) -> []; testDoubleEllipses(Config) -> ?line testDoubleEllipses:compile(Config,?BER,[]), diff --git a/lib/asn1/test/test_compile_options.erl b/lib/asn1/test/test_compile_options.erl index 5e027cdedb..5cb212eddf 100644 --- a/lib/asn1/test/test_compile_options.erl +++ b/lib/asn1/test/test_compile_options.erl @@ -24,7 +24,7 @@ -export([wrong_path/1,comp/2,path/1,ticket_6143/1,noobj/1, - record_name_prefix/1,verbose/1]). + record_name_prefix/1,verbose/1,warnings_as_errors/1]). %% OTP-5689 wrong_path(Config) -> @@ -141,6 +141,43 @@ verbose(Config) when is_list(Config) -> ?line [] = test_server:capture_get(), ok. +warnings_as_errors(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir,Config), + Asn1File = filename:join([PrivDir,"WERROR.asn1"]), + OutFile = filename:join([PrivDir,"WERROR.erl"]), + Opts = [{outdir,PrivDir},noobj,verbose], + + %% Generate WERR.asn to emit warning + %% Warning: Wrong format of type/value + %% false/{'Externalvaluereference',_,'WERR',noInvokeId} + Warn = <<"WERROR DEFINITIONS IMPLICIT TAGS ::=\n" + "\n" + "BEGIN\n" + "\n" + "InvokeId ::= CHOICE\n" + "{\n" + " present INTEGER,\n" + " absent NULL\n" + "}\n" + "\n" + "noInvokeId InvokeId ::= absent:NULL\n" + "\n" + "NoInvokeId InvokeId ::= {noInvokeId}\n" + "\n" + "END -- end of useful definitions.\n">>, + ?line ok = file:write_file(Asn1File, Warn), + + %% Test warnings_as_errors compile + ?line false = filelib:is_regular(OutFile), + ?line {error, _} = asn1ct:compile(Asn1File, [warnings_as_errors|Opts]), + ?line false = filelib:is_regular(OutFile), + + %% Test normal compile + ?line ok = asn1ct:compile(Asn1File, Opts), + ?line true = filelib:is_regular(OutFile), + ?line ok = file:delete(OutFile), + ok. + outfiles_check(OutDir) -> outfiles_check(OutDir,outfiles1()). diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl index ce8a5bf864..e46c667e47 100644 --- a/lib/compiler/src/compile.erl +++ b/lib/compiler/src/compile.erl @@ -113,7 +113,7 @@ noenv_forms(Forms, Opt) when is_atom(Opt) -> noenv_output_generated(Opts) -> {_,Passes} = passes(file, expand_opts(Opts)), - any(fun ({save_binary,_F}) -> true; + any(fun ({save_binary,_T,_F}) -> true; (_Other) -> false end, Passes). @@ -122,6 +122,7 @@ noenv_output_generated(Opts) -> %% -define(pass(P), {P,fun P/1}). +-define(pass(P,T), {P,fun T/1,fun P/1}). env_default_opts() -> Key = "ERL_COMPILER_OPTIONS", @@ -304,7 +305,7 @@ run_tc({Name,Fun}, St) -> Val. comp_ret_ok(#compile{code=Code,warnings=Warn0,module=Mod,options=Opts}=St) -> - case member(warnings_as_errors, Opts) andalso length(Warn0) > 0 of + case werror(St) of true -> case member(report_warnings, Opts) of true -> @@ -339,6 +340,11 @@ comp_ret_err(#compile{warnings=Warn0,errors=Err0,options=Opts}=St) -> false -> error end. +not_werror(St) -> not werror(St). + +werror(#compile{options=Opts,warnings=Ws}) -> + Ws =/= [] andalso member(warnings_as_errors, Opts). + %% messages_per_file([{File,[Message]}]) -> [{File,[Message]}] messages_per_file(Ms) -> T = lists:sort([{File,M} || {File,Messages} <- Ms, M <- Messages]), @@ -373,7 +379,7 @@ passes(Type, Opts) -> %% insert a first pass to remove the file (unless the %% source file is a BEAM file). {Ext,case last(Passes) of - {save_binary,_Fun} -> + {save_binary,_TestFun,_Fun} -> case Passes of [{read_beam_file,_}|_] -> %% The BEAM is both input and output. @@ -655,7 +661,7 @@ asm_passes() -> binary_passes() -> [{native_compile,fun test_native/1,fun native_compile/1}, - {unless,binary,?pass(save_binary)}]. + {unless,binary,?pass(save_binary,not_werror)}]. %%% %%% Compiler passes. @@ -1379,28 +1385,34 @@ report_errors(#compile{options=Opts,errors=Errors}) -> end. report_warnings(#compile{options=Opts,warnings=Ws0}) -> - case member(report_warnings, Opts) of + Werror = member(warnings_as_errors, Opts), + P = case Werror of + true -> ""; + false -> "Warning: " + end, + ReportWerror = Werror andalso member(report_errors, Opts), + case member(report_warnings, Opts) orelse ReportWerror of true -> - Ws1 = flatmap(fun({{F,_L},Eds}) -> format_message(F, Eds); - ({F,Eds}) -> format_message(F, Eds) end, + Ws1 = flatmap(fun({{F,_L},Eds}) -> format_message(F, P, Eds); + ({F,Eds}) -> format_message(F, P, Eds) end, Ws0), Ws = lists:sort(Ws1), foreach(fun({_,Str}) -> io:put_chars(Str) end, Ws); false -> ok end. -format_message(F, [{{Line,Column}=Loc,Mod,E}|Es]) -> - M = {{F,Loc},io_lib:format("~s:~w:~w Warning: ~s\n", - [F,Line,Column,Mod:format_error(E)])}, - [M|format_message(F, Es)]; -format_message(F, [{Line,Mod,E}|Es]) -> - M = {{F,{Line,0}},io_lib:format("~s:~w: Warning: ~s\n", - [F,Line,Mod:format_error(E)])}, - [M|format_message(F, Es)]; -format_message(F, [{Mod,E}|Es]) -> - M = {none,io_lib:format("~s: Warning: ~s\n", [F,Mod:format_error(E)])}, - [M|format_message(F, Es)]; -format_message(_, []) -> []. +format_message(F, P, [{{Line,Column}=Loc,Mod,E}|Es]) -> + M = {{F,Loc},io_lib:format("~s:~w:~w ~s~s\n", + [F,Line,Column,P,Mod:format_error(E)])}, + [M|format_message(F, P, Es)]; +format_message(F, P, [{Line,Mod,E}|Es]) -> + M = {{F,{Line,0}},io_lib:format("~s:~w: ~s~s\n", + [F,Line,P,Mod:format_error(E)])}, + [M|format_message(F, P, Es)]; +format_message(F, P, [{Mod,E}|Es]) -> + M = {none,io_lib:format("~s: ~s~s\n", [F,P,Mod:format_error(E)])}, + [M|format_message(F, P, Es)]; +format_message(_, _, []) -> []. %% list_errors(File, ErrorDescriptors) -> ok diff --git a/lib/compiler/test/error_SUITE.erl b/lib/compiler/test/error_SUITE.erl index 6e0aadf007..eb5e50818e 100644 --- a/lib/compiler/test/error_SUITE.erl +++ b/lib/compiler/test/error_SUITE.erl @@ -183,23 +183,47 @@ get_compilation_errors(Config, Filename) -> E. warnings_as_errors(Config) when is_list(Config) -> - Ts = [{warnings_as_errors, + ?line TestFile = test_filename(Config), + ?line BeamFile = filename:rootname(TestFile, ".erl") ++ ".beam", + ?line OutDir = ?config(priv_dir, Config), + + Ts1 = [{warnings_as_errors, <<" t() -> A = unused, ok. ">>, - [export_all,warnings_as_errors], - {error, - [], - [{3,erl_lint,{unused_var,'A'}}]} }], - ?line [] = run(Config, Ts), + [warnings_as_errors, export_all, {outdir, OutDir}], + {error, + [], + [{3,erl_lint,{unused_var,'A'}}]} }], + ?line [] = run(Ts1, TestFile, write_beam), + ?line false = filelib:is_regular(BeamFile), + + Ts2 = [{warning_unused_var, + <<" + t() -> + A = unused, + ok. + ">>, + [return_warnings, export_all, {outdir, OutDir}], + {warning, + [{3,erl_lint,{unused_var,'A'}}]} }], + + ?line [] = run(Ts2, TestFile, write_beam), + ?line true = filelib:is_regular(BeamFile), + ?line ok = file:delete(BeamFile), + ok. run(Config, Tests) -> + ?line File = test_filename(Config), + run(Tests, File, dont_write_beam). + +run(Tests, File, WriteBeam) -> F = fun({N,P,Ws,E}, BadL) -> - case catch run_test(Config, P, Ws) of + case catch run_test(P, File, Ws, WriteBeam) of E -> BadL; Bad -> @@ -211,8 +235,12 @@ run(Config, Tests) -> lists:foldl(F, [], Tests). run2(Config, Tests) -> + ?line File = test_filename(Config), + run2(Tests, File, dont_write_beam). + +run2(Tests, File, WriteBeam) -> F = fun({N,P,Ws,E}, BadL) -> - case catch filter(run_test(Config, P, Ws)) of + case catch filter(run_test(P, File, Ws, WriteBeam)) of E -> BadL; Bad -> @@ -231,12 +259,19 @@ filter(X) -> %% Compiles a test module and returns the list of errors and warnings. -run_test(Conf, Test0, Warnings) -> - Filename = 'errors_test.erl', - ?line DataDir = ?config(priv_dir, Conf), +test_filename(Conf) -> + Filename = "errors_test.erl", + DataDir = ?config(priv_dir, Conf), + filename:join(DataDir, Filename). + +run_test(Test0, File, Warnings, WriteBeam) -> ?line Test = ["-module(errors_test). ", Test0], - ?line File = filename:join(DataDir, Filename), - ?line Opts = [binary,return_errors|Warnings], + ?line Opts = case WriteBeam of + dont_write_beam -> + [binary,return_errors|Warnings]; + write_beam -> + [return_errors|Warnings] + end, ?line ok = file:write_file(File, Test), %% Compile once just to print all errors and warnings. @@ -252,6 +287,10 @@ run_test(Conf, Test0, Warnings) -> %io:format("compile:file(~s,~p) ->~n~p~n", % [File,Opts,Ws]), []; + {ok,errors_test,[{_File,Ws}]} -> + {warning,Ws}; + {ok,errors_test,[]} -> + []; {error,[{XFile,Es}],Ws} = _ZZ when is_list(XFile) -> %io:format("compile:file(~s,~p) ->~n~p~n", % [File,Opts,_ZZ]), diff --git a/lib/parsetools/src/leex.erl b/lib/parsetools/src/leex.erl index 942e9928b1..cdf20461d9 100644 --- a/lib/parsetools/src/leex.erl +++ b/lib/parsetools/src/leex.erl @@ -73,12 +73,15 @@ %%% Interface to erl_compile. compile(Input0, Output0, - #options{warning = WarnLevel, verbose=Verbose, includes=Includes}) -> + #options{warning = WarnLevel, verbose=Verbose, includes=Includes, + specific=Specific}) -> Input = assure_extension(shorten_filename(Input0), ".xrl"), Output = assure_extension(shorten_filename(Output0), ".erl"), Includefile = lists:sublist(Includes, 1), + Werror = proplists:get_bool(warnings_as_errors, Specific), Opts = [{scannerfile,Output},{includefile,Includefile},{verbose,Verbose}, - {report_errors,true},{report_warnings,WarnLevel > 0}], + {report_errors,true},{report_warnings,WarnLevel > 0}, + {warnings_as_errors, Werror}], case file(Input, Opts) of {ok, _} -> ok; @@ -107,7 +110,7 @@ file(File, Opts0) -> St = try {ok,REAs,Actions,Code,St2} = parse_file(St1), {DFA,DF} = make_dfa(REAs, St2), - case werr(St2) of + case werror(St2) of false -> St3 = out_file(St2, DFA, DF, Actions, Code), case lists:member(dfa_graph, St3#leex.opts) of @@ -259,9 +262,9 @@ leex_ret(St) -> report_warnings(St), Es = pack_errors(St#leex.errors), Ws = pack_warnings(St#leex.warnings), - Werr = werr(St), + Werror = werror(St), if - Werr -> + Werror -> do_error_return(St, Es, Ws); Es =:= [] -> case member(return_warnings, St#leex.opts) of @@ -278,9 +281,9 @@ do_error_return(St, Es, Ws) -> false -> error end. -werr(St) -> - member(warnings_as_errors, St#leex.opts) - andalso length(St#leex.warnings) > 0. +werror(St) -> + St#leex.warnings =/= [] + andalso member(warnings_as_errors, St#leex.opts). pack_errors([{File,_} | _] = Es) -> [{File, flatmap(fun({_,E}) -> [E] end, sort(Es))}]; @@ -304,15 +307,24 @@ report_errors(St) -> end, report_errors, St#leex.opts). report_warnings(St) -> - when_opt(fun () -> - foreach(fun({File,{none,Mod,W}}) -> - io:fwrite("~s: Warning: ~s\n", - [File,Mod:format_error(W)]); - ({File,{Line,Mod,W}}) -> - io:fwrite("~s:~w: Warning: ~s\n", - [File,Line,Mod:format_error(W)]) - end, sort(St#leex.warnings)) - end, report_warnings, St#leex.opts). + Werror = member(warnings_as_errors, St#leex.opts), + Prefix = case Werror of + true -> ""; + false -> "Warning: " + end, + ReportWerror = Werror andalso member(report_errors, St#leex.opts), + ShouldReport = member(report_warnings, St#leex.opts) orelse ReportWerror, + when_bool(fun () -> + foreach(fun({File,{none,Mod,W}}) -> + io:fwrite("~s: ~s~s\n", + [File,Prefix, + Mod:format_error(W)]); + ({File,{Line,Mod,W}}) -> + io:fwrite("~s:~w: ~s~s\n", + [File,Line,Prefix, + Mod:format_error(W)]) + end, sort(St#leex.warnings)) + end, ShouldReport). -spec add_error(_, #leex{}) -> no_return(). add_error(E, St) -> @@ -360,6 +372,12 @@ when_opt(Do, Opt, Opts) -> false -> ok end. +when_bool(Do, Bool) -> + case Bool of + true -> Do(); + false -> ok + end. + verbose_print(St, Format, Args) -> when_opt(fun () -> io:fwrite(Format, Args) end, verbose, St#leex.opts). diff --git a/lib/parsetools/src/yecc.erl b/lib/parsetools/src/yecc.erl index 72cff3af92..354d56527d 100644 --- a/lib/parsetools/src/yecc.erl +++ b/lib/parsetools/src/yecc.erl @@ -133,12 +133,15 @@ %%% Interface to erl_compile. compile(Input0, Output0, - #options{warning = WarnLevel, verbose=Verbose, includes=Includes}) -> + #options{warning = WarnLevel, verbose=Verbose, includes=Includes, + specific=Specific}) -> Input = shorten_filename(Input0), Output = shorten_filename(Output0), Includefile = lists:sublist(Includes, 1), + Werror = proplists:get_bool(warnings_as_errors, Specific), Opts = [{parserfile,Output}, {includefile,Includefile}, {verbose,Verbose}, - {report_errors, true}, {report_warnings, WarnLevel > 0}], + {report_errors, true}, {report_warnings, WarnLevel > 0}, + {warnings_as_errors, Werror}], case file(Input, Opts) of {ok, _OutFile} -> ok; @@ -411,15 +414,15 @@ infile(Parent, Infilex, Options) -> {error, Reason} -> add_error(St0#yecc.infile, none, {file_error, Reason}, St0) end, - case {St#yecc.errors, werr(St)} of + case {St#yecc.errors, werror(St)} of {[], false} -> ok; _ -> _ = file:delete(St#yecc.outfile) end, Parent ! {self(), yecc_ret(St)}. -werr(St) -> - member(warnings_as_errors, St#yecc.options) - andalso length(St#yecc.warnings) > 0. +werror(St) -> + St#yecc.warnings =/= [] + andalso member(warnings_as_errors, St#yecc.options). outfile(St0) -> case file:open(St0#yecc.outfile, [write, delayed_write]) of @@ -783,9 +786,9 @@ yecc_ret(St0) -> report_warnings(St), Es = pack_errors(St#yecc.errors), Ws = pack_warnings(St#yecc.warnings), - Werr = werr(St), + Werror = werror(St), if - Werr -> + Werror -> do_error_return(St, Es, Ws); Es =:= [] -> case member(return_warnings, St#yecc.options) of @@ -849,14 +852,22 @@ report_errors(St) -> end. report_warnings(St) -> - case member(report_warnings, St#yecc.options) of + Werror = member(warnings_as_errors, St#yecc.options), + Prefix = case Werror of + true -> ""; + false -> "Warning: " + end, + ReportWerror = Werror andalso member(report_errors, St#yecc.options), + case member(report_warnings, St#yecc.options) orelse ReportWerror of true -> foreach(fun({File,{none,Mod,W}}) -> - io:fwrite(<<"~s: Warning: ~s\n">>, - [File,Mod:format_error(W)]); + io:fwrite(<<"~s: ~s~s\n">>, + [File,Prefix, + Mod:format_error(W)]); ({File,{Line,Mod,W}}) -> - io:fwrite(<<"~s:~w: Warning: ~s\n">>, - [File,Line,Mod:format_error(W)]) + io:fwrite(<<"~s:~w: ~s~s\n">>, + [File,Line,Prefix, + Mod:format_error(W)]) end, sort(St#yecc.warnings)); false -> ok diff --git a/lib/parsetools/test/leex_SUITE.erl b/lib/parsetools/test/leex_SUITE.erl index 48312445ef..1e50aedf07 100644 --- a/lib/parsetools/test/leex_SUITE.erl +++ b/lib/parsetools/test/leex_SUITE.erl @@ -152,6 +152,7 @@ file(Config) when is_list(Config) -> ?line writable(Dotfile), file:delete(Dotfile), + ok = file:delete(Scannerfile), Warn = <<"Definitions.1998\n" "D = [0-9]\n" "Rules.\n" @@ -159,11 +160,15 @@ file(Config) when is_list(Config) -> "Erlang code.\n">>, ok = file:write_file(Filename, Warn), error = leex:file(Filename, [warnings_as_errors]), + false = filelib:is_regular(Scannerfile), error = leex:file(Filename, [return_warnings,warnings_as_errors]), - {ok,Scannerfile,[{Filename,[{1,leex,ignored_characters}]}]} = - leex:file(Filename, [return_warnings]), + false = filelib:is_regular(Scannerfile), {error,_,[{Filename,[{1,leex,ignored_characters}]}]} = - leex:file(Filename, [return_errors,warnings_as_errors]), + leex:file(Filename, [return_errors,warnings_as_errors]), + false = filelib:is_regular(Scannerfile), + {ok,Scannerfile,[{Filename,[{1,leex,ignored_characters}]}]} = + leex:file(Filename, [return_warnings]), + true = filelib:is_regular(Scannerfile), file:delete(Filename), ok. diff --git a/lib/parsetools/test/yecc_SUITE.erl b/lib/parsetools/test/yecc_SUITE.erl index 0133524950..a5f66b48e9 100644 --- a/lib/parsetools/test/yecc_SUITE.erl +++ b/lib/parsetools/test/yecc_SUITE.erl @@ -173,6 +173,7 @@ syntax(Config) when is_list(Config) -> %% Report errors. Very simple test of format_error/1. Ret = [return, {report, true}], Filename = filename:join(Dir, "file.yrl"), + Parserfile = filename:join(Dir, "file.erl"), Parserfile1 = filename:join(Dir, "a file"), ?line ok = file:write_file(Filename, <<"">>), @@ -248,12 +249,17 @@ syntax(Config) when is_list(Config) -> yecc:file(Filename, Ret), %% Bad declaration with warnings_as_errors. + ok = file:delete(Parserfile), error = yecc:file(Filename, [warnings_as_errors]), + false = filelib:is_regular(Parserfile), error = yecc:file(Filename, [return_warnings,warnings_as_errors]), - {ok,_,[{_,[{2,yecc,bad_declaration}]}]} = - yecc:file(Filename, [return_warnings]), + false = filelib:is_regular(Parserfile), {error,_,[{_,[{2,yecc,bad_declaration}]}]} = yecc:file(Filename, [return_errors,warnings_as_errors]), + false = filelib:is_regular(Parserfile), + {ok,_,[{_,[{2,yecc,bad_declaration}]}]} = + yecc:file(Filename, [return_warnings]), + true = filelib:is_regular(Parserfile), %% Bad declaration. ?line ok = file:write_file(Filename, diff --git a/lib/sasl/doc/src/systools.xml b/lib/sasl/doc/src/systools.xml index 883c9c372b..8c1c327d74 100644 --- a/lib/sasl/doc/src/systools.xml +++ b/lib/sasl/doc/src/systools.xml @@ -45,7 +45,8 @@ <v>Name = string()</v> <v>UpFrom = DownTo = [Name | {Name,Descr}]</v> <v> Descr = term()</v> - <v>Opt = {path,[Dir]} | restart_emulator | silent | noexec | {outdir,Dir}</v> + <v>Opt = {path,[Dir]} | restart_emulator | silent | noexec | {outdir,Dir} + | warnings_as_errors</v> <v> Dir = string()</v> <v>Result = ok | error | {ok,Relup,Module,Warnings} | {error,Module,Error}</v> <v> Relup - see relup(4)</v> @@ -122,6 +123,8 @@ <p>If the option <c>noexec</c> is provided, the function returns the same values as for <c>silent</c> but no <c>relup</c> file is created.</p> + <p>If the option <c>warnings_as_errors</c> is provided, warnings + are treated as errors.</p> </desc> </func> <func> @@ -130,7 +133,8 @@ <fsummary>Generate a boot script <c>.script/.boot</c>.</fsummary> <type> <v>Name = string()</v> - <v>Opt = src_tests | {path,[Dir]} | local | {variables,[Var]} | exref | {exref,[App]}] | silent | {outdir,Dir}</v> + <v>Opt = src_tests | {path,[Dir]} | local | {variables,[Var]} | exref | {exref,[App]}] + | silent | {outdir,Dir} | warnings_as_errors</v> <v> Dir = string()</v> <v> Var = {VarName,Prefix}</v> <v> VarName = Prefix = string()</v> @@ -232,6 +236,8 @@ Warnings and errors can be converted to strings by calling <c>Module:format_warning(Warnings)</c> or <c>Module:format_error(Error)</c>.</p> + <p>If the option <c>warnings_as_errors</c> is provided, warnings + are treated as errors.</p> </desc> </func> <func> diff --git a/lib/sasl/src/systools_lib.erl b/lib/sasl/src/systools_lib.erl index f951647b79..1b6ea125d9 100644 --- a/lib/sasl/src/systools_lib.erl +++ b/lib/sasl/src/systools_lib.erl @@ -24,7 +24,7 @@ %% -export([file_term2binary/2, read_term/1, read_term_from_stream/2, - get_dirs/1, get_path/1]). + get_dirs/1, get_path/1, werror/2]). -include_lib("kernel/include/file.hrl"). @@ -219,6 +219,7 @@ flat([H|T], Ack) -> flat(T, [H|Ack]); flat([], Ack) -> lists:reverse(Ack). - - + +werror(Options, Warnings) -> + lists:member(warnings_as_errors, Options) andalso Warnings =/= []. diff --git a/lib/sasl/src/systools_make.erl b/lib/sasl/src/systools_make.erl index 5dc83e7b2a..7f400f5cce 100644 --- a/lib/sasl/src/systools_make.erl +++ b/lib/sasl/src/systools_make.erl @@ -44,10 +44,12 @@ %%----------------------------------------------------------------- %% Create a boot script from a release file. -%% Options is a list of {path, Path} | silent | local where path sets -%% the search path, silent supresses error message printing on console, -%% local generates a script with references to the directories there -%% the applications are found. +%% Options is a list of {path, Path} | silent | local +%% | warnings_as_errors +%% where path sets the search path, silent supresses error message +%% printing on console, local generates a script with references +%% to the directories there the applications are found, +%% and warnings_as_errors treats warnings as errors. %% %% New options: {path,Path} can contain wildcards %% src_tests @@ -85,11 +87,16 @@ make_script(RelName, Output, Flags) when is_list(RelName), ModTestP = {member(src_tests, Flags),xref_p(Flags)}, case get_release(RelName, Path, ModTestP, machine(Flags)) of {ok, Release, Appls, Warnings} -> - case generate_script(Output,Release,Appls,Flags) of - ok -> + case systools_lib:werror(Flags, Warnings) of + true -> return(ok,Warnings,Flags); - Error -> - return(Error,Warnings,Flags) + false -> + case generate_script(Output,Release,Appls,Flags) of + ok -> + return(ok,Warnings,Flags); + Error -> + return(Error,Warnings,Flags) + end end; Error -> return(Error,[],Flags) @@ -130,10 +137,21 @@ get_outdir(Flags) -> return(ok,Warnings,Flags) -> case member(silent,Flags) of true -> - {ok,?MODULE,Warnings}; + case systools_lib:werror(Flags, Warnings) of + true -> + error; + false -> + {ok,?MODULE,Warnings} + end; _ -> - io:format("~s",[format_warning(Warnings)]), - ok + case member(warnings_as_errors,Flags) of + true -> + io:format("~s",[format_warning(Warnings, true)]), + error; + false -> + io:format("~s",[format_warning(Warnings)]), + ok + end end; return({error,Mod,Error},_,Flags) -> case member(silent,Flags) of @@ -1833,78 +1851,89 @@ get_flag(_,_) -> false. %% Check Options for make_script check_args_script(Args) -> cas(Args, - {undef, undef, undef, undef, undef, undef, undef, undef, []}). + {undef, undef, undef, undef, undef, undef, undef, undef, + undef, []}). -cas([], {_Path,_Sil,_Loc,_Test,_Var,_Mach,_Xref,_XrefApps, X}) -> +cas([], {_Path,_Sil,_Loc,_Test,_Var,_Mach,_Xref,_XrefApps,_Werror, X}) -> X; %%% path --------------------------------------------------------------- -cas([{path, P} | Args], {Path, Sil, Loc, Test, Var, Mach, - Xref, XrefApps, X}) when is_list(P) -> +cas([{path, P} | Args], {Path, Sil, Loc, Test, Var, Mach, Xref, + XrefApps, Werror, X}) when is_list(P) -> case check_path(P) of ok -> - cas(Args, {P, Sil, Loc, Test, Var, Mach, Xref, XrefApps,X}); + cas(Args, {P, Sil, Loc, Test, Var, Mach, Xref, XrefApps, + Werror, X}); error -> cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, - X++[{path,P}]}) + Werror, X++[{path,P}]}) end; %%% silent ------------------------------------------------------------- -cas([silent | Args], {Path, _Sil, Loc, Test, Var, Mach, - Xref, XrefApps, X}) -> - cas(Args, {Path, silent, Loc, Test, Var, Mach, Xref, XrefApps, X}); +cas([silent | Args], {Path, _Sil, Loc, Test, Var, Mach, Xref, + XrefApps, Werror, X}) -> + cas(Args, {Path, silent, Loc, Test, Var, Mach, Xref, XrefApps, + Werror, X}); %%% local -------------------------------------------------------------- -cas([local | Args], {Path, Sil, _Loc, Test, Var, Mach, - Xref, XrefApps, X}) -> - cas(Args, {Path, Sil, local, Test, Var, Mach, Xref, XrefApps, X}); +cas([local | Args], {Path, Sil, _Loc, Test, Var, Mach, Xref, + XrefApps, Werror, X}) -> + cas(Args, {Path, Sil, local, Test, Var, Mach, Xref, XrefApps, + Werror, X}); %%% src_tests ------------------------------------------------------- -cas([src_tests | Args], {Path, Sil, Loc, _Test, Var, Mach, - Xref, XrefApps, X}) -> +cas([src_tests | Args], {Path, Sil, Loc, _Test, Var, Mach, Xref, + XrefApps, Werror, X}) -> cas(Args, - {Path, Sil, Loc, src_tests, Var, Mach, Xref, XrefApps,X}); + {Path, Sil, Loc, src_tests, Var, Mach, Xref, Werror, XrefApps,X}); %%% variables ---------------------------------------------------------- -cas([{variables, V} | Args], {Path, Sil, Loc, Test, Var, Mach, - Xref, XrefApps, X}) when is_list(V) -> +cas([{variables, V} | Args], {Path, Sil, Loc, Test, Var, Mach, Xref, + XrefApps, Werror, X}) when is_list(V) -> case check_vars(V) of ok -> cas(Args, - {Path, Sil, Loc, Test, V, Mach, Xref, XrefApps, X}); + {Path, Sil, Loc, Test, V, Mach, Xref, XrefApps, Werror, X}); error -> cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, - X++[{variables, V}]}) + Werror, X++[{variables, V}]}) end; %%% machine ------------------------------------------------------------ -cas([{machine, M} | Args], {Path, Sil, Loc, Test, Var, Mach, - Xref, XrefApps, X}) when is_atom(M) -> - cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, X}); +cas([{machine, M} | Args], {Path, Sil, Loc, Test, Var, Mach, Xref, + XrefApps, Werror, X}) when is_atom(M) -> + cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, Werror, X}); %%% exref -------------------------------------------------------------- -cas([exref | Args], {Path, Sil, Loc, Test, Var, Mach, - _Xref, XrefApps, X}) -> - cas(Args, {Path, Sil, Loc, Test, Var, Mach, exref, XrefApps, X}); +cas([exref | Args], {Path, Sil, Loc, Test, Var, Mach, _Xref, + XrefApps, Werror, X}) -> + cas(Args, {Path, Sil, Loc, Test, Var, Mach, exref, XrefApps, Werror, X}); %%% exref Apps --------------------------------------------------------- -cas([{exref, Apps} | Args], {Path, Sil, Loc, Test, Var, Mach, - Xref, XrefApps, X}) when is_list(Apps) -> +cas([{exref, Apps} | Args], {Path, Sil, Loc, Test, Var, Mach, Xref, + XrefApps, Werror, X}) when is_list(Apps) -> case check_apps(Apps) of ok -> cas(Args, {Path, Sil, Loc, Test, Var, Mach, - Xref, Apps, X}); + Xref, Apps, Werror, X}); error -> cas(Args, {Path, Sil, Loc, Test, Var, Mach, - Xref, XrefApps, X++[{exref, Apps}]}) + Xref, XrefApps, Werror, X++[{exref, Apps}]}) end; %%% outdir Dir --------------------------------------------------------- -cas([{outdir, Dir} | Args], {Path, Sil, Loc, Test, Var, Mach, - Xref, XrefApps, X}) when is_list(Dir) -> - cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, X}); +cas([{outdir, Dir} | Args], {Path, Sil, Loc, Test, Var, Mach, Xref, + XrefApps, Werror, X}) when is_list(Dir) -> + cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, Werror, X}); %%% otp_build (secret, not documented) --------------------------------- -cas([otp_build | Args], {Path, Sil, Loc, Test, Var, Mach, - Xref, XrefApps, X}) -> - cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, X}); +cas([otp_build | Args], {Path, Sil, Loc, Test, Var, Mach, Xref, + XrefApps, Werror, X}) -> + cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, Werror, X}); %%% no_module_tests (kept for backwards compatibility, but ignored) ---- -cas([no_module_tests | Args], {Path, Sil, Loc, Test, Var, Mach, - Xref, XrefApps, X}) -> - cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps,X}); +cas([no_module_tests | Args], {Path, Sil, Loc, Test, Var, Mach, Xref, + XrefApps, Werror, X}) -> + cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, Werror, X}); +%%% warnings_as_errors (kept for backwards compatibility, but ignored) ---- +cas([warnings_as_errors | Args], {Path, Sil, Loc, Test, Var, Mach, Xref, + XrefApps, _Werror, X}) -> + cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, + warnings_as_errors, X}); %%% ERROR -------------------------------------------------------------- -cas([Y | Args], {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, X}) -> - cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps,X++[Y]}). +cas([Y | Args], {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, + Werror, X}) -> + cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, Werror, + X++[Y]}). @@ -2030,7 +2059,6 @@ check_apps([H|T]) when is_atom(H) -> check_apps(_) -> error. - %% Format error format_error(badly_formatted_release) -> @@ -2144,21 +2172,31 @@ form_tar_err({add, File, Error}) -> %% Format warning format_warning(Warnings) -> - map(fun({warning,W}) -> form_warn(W) end, Warnings). - -form_warn({source_not_found,{Mod,_,App,_,_}}) -> - io_lib:format("*WARNING* ~p: Source code not found: ~p.erl~n", - [App,Mod]); -form_warn({{parse_error, File},{_,_,App,_,_}}) -> - io_lib:format("*WARNING* ~p: Parse error: ~p~n", - [App,File]); -form_warn({obj_out_of_date,{Mod,_,App,_,_}}) -> - io_lib:format("*WARNING* ~p: Object code (~p) out of date~n",[App,Mod]); -form_warn({exref_undef, Undef}) -> - F = fun({M,F,A}) -> - io_lib:format("*WARNING* Undefined function ~p:~p/~p~n", - [M,F,A]) + format_warning(Warnings, false). + +format_warning(Warnings, Werror) -> + Prefix = case Werror of + true -> + ""; + false -> + "*WARNING* " + end, + map(fun({warning,W}) -> form_warn(Prefix, W) end, Warnings). + +form_warn(Prefix, {source_not_found,{Mod,_,App,_,_}}) -> + io_lib:format("~s~p: Source code not found: ~p.erl~n", + [Prefix,App,Mod]); +form_warn(Prefix, {{parse_error, File},{_,_,App,_,_}}) -> + io_lib:format("~s~p: Parse error: ~p~n", + [Prefix,App,File]); +form_warn(Prefix, {obj_out_of_date,{Mod,_,App,_,_}}) -> + io_lib:format("~s~p: Object code (~p) out of date~n", + [Prefix,App,Mod]); +form_warn(Prefix, {exref_undef, Undef}) -> + F = fun({M,F,A}) -> + io_lib:format("~sUndefined function ~p:~p/~p~n", + [Prefix,M,F,A]) end, map(F, Undef); -form_warn(What) -> - io_lib:format("*WARNING* ~p~n", [What]). +form_warn(Prefix, What) -> + io_lib:format("~s ~p~n", [Prefix,What]). diff --git a/lib/sasl/src/systools_relup.erl b/lib/sasl/src/systools_relup.erl index ec5486226c..6d9e922900 100644 --- a/lib/sasl/src/systools_relup.erl +++ b/lib/sasl/src/systools_relup.erl @@ -122,7 +122,7 @@ %% rel_filename() = description() = string() %% Opts = [opt()] %% opt() = {path, [path()]} | silent | noexec | restart_emulator -%% | {outdir, string()} +%% | {outdir, string()} | warnings_as_errors %% path() = [string()] %% Ret = ok | error | {ok, Relup, Module, Warnings} | {error, Module, Error} %% @@ -139,8 +139,9 @@ %% %% The option `path' sets search path, `silent' suppresses printing of %% error messages to the console, `noexec' inhibits the creation of -%% the output "relup" file, and restart_emulator ensures that the new -%% emulator is restarted (as the final step). +%% the output "relup" file, restart_emulator ensures that the new +%% emulator is restarted (as the final step), and `warnings_as_errors' +%% treats warnings as errors. %% ---------------------------------------------------------------- mk_relup(TopRelFile, BaseUpRelDcs, BaseDnRelDcs) -> mk_relup(TopRelFile, BaseUpRelDcs, BaseDnRelDcs, []). @@ -153,14 +154,29 @@ mk_relup(TopRelFile, BaseUpRelDcs, BaseDnRelDcs, Opts) -> {false, false} -> case R of {ok, _Res, _Mod, Ws} -> - print_warnings(Ws), - ok; + print_warnings(Ws, Opts), + case systools_lib:werror(Opts, Ws) of + true -> + error; + false -> + ok + end; Other -> print_error(Other), error end; - _ -> - R + _ -> + case R of + {ok, _Res, _Mod, Ws} -> + case systools_lib:werror(Opts, Ws) of + true -> + error; + false -> + R + end; + R -> + R + end end; BadArg -> erlang:error({badarg, BadArg}) @@ -195,7 +211,12 @@ do_mk_relup(TopRelFile, BaseUpRelDcs, BaseDnRelDcs, Path, Opts) -> {Dn, Ws2} = foreach_baserel_dn(TopRel, TopApps, BaseDnRelDcs, Path, Opts, Ws1), Relup = {TopRel#release.vsn, Up, Dn}, - write_relup_file(Relup, Opts), + case systools_lib:werror(Opts, Ws2) of + true -> + ok; + false -> + write_relup_file(Relup, Opts) + end, {ok, Relup, ?MODULE, Ws2}; Other -> throw(Other) @@ -527,20 +548,29 @@ format_error(Error) -> io:format("~p~n", [Error]). -print_warnings(Ws) when is_list(Ws) -> - lists:foreach(fun(W) -> print_warning(W) end, Ws); -print_warnings(W) -> - print_warning(W). +print_warnings(Ws, Opts) when is_list(Ws) -> + lists:foreach(fun(W) -> print_warning(W, Opts) end, Ws); +print_warnings(W, Opts) -> + print_warning(W, Opts). -print_warning(W) -> - S = format_warning(W), +print_warning(W, Opts) -> + Prefix = case lists:member(warnings_as_errors, Opts) of + true -> + ""; + false -> + "*WARNING* " + end, + S = format_warning(Prefix, W), io:format("~s", [S]). -format_warning({erts_vsn_changed, {Rel1, Rel2}}) -> - io_lib:format("*WARNING* The ERTS version changed between ~p and ~p~n", - [Rel1, Rel2]); -format_warning(What) -> - io_lib:format("*WARNING* ~p~n",[What]). +format_warning(W) -> + format_warning("*WARNING* ", W). + +format_warning(Prefix, {erts_vsn_changed, {Rel1, Rel2}}) -> + io_lib:format("~sThe ERTS version changed between ~p and ~p~n", + [Prefix, Rel1, Rel2]); +format_warning(Prefix, What) -> + io_lib:format("~s~p~n",[Prefix, What]). get_reason({error, {open, _, _}}) -> open; diff --git a/lib/sasl/test/systools_SUITE.erl b/lib/sasl/test/systools_SUITE.erl index 539f6de99d..e352247d44 100644 --- a/lib/sasl/test/systools_SUITE.erl +++ b/lib/sasl/test/systools_SUITE.erl @@ -396,6 +396,7 @@ src_tests_script(Config) when is_list(Config) -> ?line PSAVE = code:get_path(), % Save path ?line {LatestDir, LatestName} = create_script(latest,Config), + ?line BootFile = LatestName ++ ".boot", ?line DataDir = filename:absname(?copydir), ?line LibDir = fname([DataDir, d_missing_src, lib]), @@ -416,14 +417,32 @@ src_tests_script(Config) when is_list(Config) -> ?line Erl2 = filename:join([P1,"..","src","db2.erl"]), ?line file:delete(Erl2), - %% Then make script - two warnings should be issued when - %% src_tests is given + %% Then make script + + %% .boot file should not exist + ?line ok = file:delete(BootFile), + ?line false = filelib:is_regular(BootFile), + %% With warnings_as_errors and src_tests option, an error should be issued + ?line error = + systools:make_script(LatestName, [silent, {path, N}, src_tests, + warnings_as_errors]), + ?line error = + systools:make_script(LatestName, [{path, N}, src_tests, + warnings_as_errors]), + + %% due to warnings_as_errors .boot file should still not exist + ?line false = filelib:is_regular(BootFile), + + %% Two warnings should be issued when src_tests is given %% 1. old object code for db1.beam %% 2. missing source code for db2.beam ?line {ok, _, [{warning,{obj_out_of_date,_}}, {warning,{source_not_found,_}}]} = systools:make_script(LatestName, [silent, {path, N}, src_tests]), + %% .boot file should exist now + ?line true = filelib:is_regular(BootFile), + %% Without the src_tests option, no warning should be issued ?line {ok, _, []} = systools:make_script(LatestName, [silent, {path, N}]), @@ -1150,6 +1169,21 @@ normal_relup(Config) when is_list(Config) -> [{path, P}, silent]), ?line ok = check_relup([{db, "2.1"}], [{db, "1.0"}]), + %% file should not be written if warnings_as_errors is enabled. + %% delete before running tests. + ?line ok = file:delete("relup"), + + %% Check that warnings are treated as errors + ?line error = + systools:make_relup(LatestName, [LatestName2], [LatestName1], + [{path, P}, warnings_as_errors]), + ?line error = + systools:make_relup(LatestName, [LatestName2], [LatestName1], + [{path, P}, silent, warnings_as_errors]), + + %% relup file should not exist + ?line false = filelib:is_regular("relup"), + %% Check that warnings get through ?line ok = systools:make_relup(LatestName, [LatestName2], [LatestName1], [{path, P}]), @@ -1159,6 +1193,9 @@ normal_relup(Config) when is_list(Config) -> [{path, P}, silent]), ?line ok = check_relup([{fe, "3.1"}, {db, "2.1"}], [{db, "1.0"}]), + %% relup file should exist now + ?line true = filelib:is_regular("relup"), + ?line ok = file:set_cwd(OldDir), ok. diff --git a/lib/snmp/test/snmp_compiler_test.erl b/lib/snmp/test/snmp_compiler_test.erl index cee11ba97a..c964b08168 100644 --- a/lib/snmp/test/snmp_compiler_test.erl +++ b/lib/snmp/test/snmp_compiler_test.erl @@ -47,7 +47,7 @@ module_identity/1, agent_capabilities/1, module_compliance/1, - warnings_as_errors/1, + warnings_as_errors/1, otp_6150/1, otp_8574/1, @@ -101,7 +101,7 @@ all() -> module_identity, agent_capabilities, module_compliance, - warnings_as_errors, + warnings_as_errors, {group, tickets} ]. @@ -282,8 +282,8 @@ warnings_as_errors(Config) when is_list(Config) -> MibDir = ?config(mib_dir, Config), MibFile = join(MibDir, "OTP8574-MIB.mib"), OutFile = join(Dir, "OTP8574-MIB.bin"), - Opts = [{group_check, false}, - {outdir, Dir}, + Opts = [{group_check, false}, + {outdir, Dir}, {verbosity, trace}, relaxed_row_name_assign_check], {error, compilation_failed} = @@ -291,6 +291,7 @@ warnings_as_errors(Config) when is_list(Config) -> false = filelib:is_regular(OutFile), {ok, _} = snmpc:compile(MibFile, Opts), true = filelib:is_regular(OutFile), + ok = file:delete(OutFile), ok. |