Skip to content

Commit 18e8908

Browse files
committed
[build] Gracefully error when a module has conflicting compiler options
1 parent f5c08a5 commit 18e8908

File tree

4 files changed

+116
-41
lines changed

4 files changed

+116
-41
lines changed

src/build.m

Lines changed: 52 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -417,36 +417,39 @@ not is_empty(DupModules)
417417
io::di, io::uo) is det.
418418

419419
build_dependency_info(Targets, MaybeDeps, !DirInfo, !IO) :-
420-
Modules0 = make_module_info(Targets),
421-
422-
% The term Target is overloaded here, it means both the whole things
423-
% that plzbuild is trying to build, but also the steps that ninja does
424-
% to build them.
425-
map_foldl2(find_module_file, Modules0, MaybeModules0, !DirInfo, !IO),
426-
MaybeModules = result_list_to_result(MaybeModules0),
427-
find_foreign_sources(Targets, MaybeForeignSources, !DirInfo, !IO),
428-
429-
( MaybeModules = ok(Modules),
430-
MaybeForeignSources = ok(ForeignSources),
431-
ModuleTargets = map(make_module_targets, Modules),
432-
ProgramTargets = map(make_program_target, Targets),
433-
ForeignLinkTargets = condense(map(make_foreign_link_targets,
434-
Targets)),
435-
ForeignCompileTargets = map(make_foreign_target, ForeignSources),
436-
437-
MaybeDeps = ok(condense(ModuleTargets) ++
438-
ForeignCompileTargets ++
439-
ForeignLinkTargets ++ ProgramTargets)
440-
441-
; MaybeModules = ok(_),
442-
MaybeForeignSources = errors(Errors),
443-
MaybeDeps = errors(Errors)
444-
; MaybeModules = errors(Errors),
445-
MaybeForeignSources = ok(_),
420+
MaybeModules0 = make_module_info(Targets),
421+
( MaybeModules0 = ok(Modules0),
422+
% The term Target is overloaded here, it means both the whole things
423+
% that plzbuild is trying to build, but also the steps that ninja does
424+
% to build them.
425+
map_foldl2(find_module_file, Modules0, MaybeModules1, !DirInfo, !IO),
426+
MaybeModules = result_list_to_result(MaybeModules1),
427+
find_foreign_sources(Targets, MaybeForeignSources, !DirInfo, !IO),
428+
429+
( MaybeModules = ok(Modules),
430+
MaybeForeignSources = ok(ForeignSources),
431+
ModuleTargets = map(make_module_targets, Modules),
432+
ProgramTargets = map(make_program_target, Targets),
433+
ForeignLinkTargets = condense(map(make_foreign_link_targets,
434+
Targets)),
435+
ForeignCompileTargets = map(make_foreign_target, ForeignSources),
436+
437+
MaybeDeps = ok(condense(ModuleTargets) ++
438+
ForeignCompileTargets ++
439+
ForeignLinkTargets ++ ProgramTargets)
440+
441+
; MaybeModules = ok(_),
442+
MaybeForeignSources = errors(Errors),
443+
MaybeDeps = errors(Errors)
444+
; MaybeModules = errors(Errors),
445+
MaybeForeignSources = ok(_),
446+
MaybeDeps = errors(Errors)
447+
; MaybeModules = errors(ErrorsA),
448+
MaybeForeignSources = errors(ErrorsB),
449+
MaybeDeps = errors(ErrorsA ++ ErrorsB)
450+
)
451+
; MaybeModules0 = errors(Errors),
446452
MaybeDeps = errors(Errors)
447-
; MaybeModules = errors(ErrorsA),
448-
MaybeForeignSources = errors(ErrorsB),
449-
MaybeDeps = errors(ErrorsA ++ ErrorsB)
450453
).
451454

452455
:- type module_info
@@ -457,12 +460,16 @@ not is_empty(DupModules)
457460
mi_pcflags :: string
458461
).
459462

460-
:- func make_module_info(list(target)) = list(module_info).
463+
:- func make_module_info(list(target)) = result(list(module_info), string).
461464

462465
make_module_info(Targets) = Modules :-
463466
Modules0 = condense(map(target_get_modules, Targets)),
464-
foldl(resolve_duplicate_modules, Modules0, init, Modules1),
465-
Modules = map.values(Modules1).
467+
foldl_result(resolve_duplicate_modules, Modules0, init, MaybeModules1),
468+
( MaybeModules1 = ok(Modules1),
469+
Modules = ok(map.values(Modules1))
470+
; MaybeModules1 = errors(Error),
471+
Modules = errors(Error)
472+
).
466473

467474
:- func target_get_modules(target) = list(module_info).
468475

@@ -473,30 +480,34 @@ not is_empty(DupModules)
473480
Target ^ t_modules).
474481

475482
:- pred resolve_duplicate_modules(module_info::in,
476-
map(q_name, module_info)::in, map(q_name, module_info)::out) is det.
483+
map(q_name, module_info)::in,
484+
result(map(q_name, module_info), string)::out) is det.
477485

478486
resolve_duplicate_modules(Module, !Map) :-
479487
Name = Module ^ mi_name,
480-
map_set_or_update(func(M) = module_merge(M, Module),
488+
map_set_or_update_result(func(M) = module_merge(M, Module),
481489
Name, Module, !Map).
482490

483-
:- func module_merge(module_info, module_info) = module_info.
491+
:- func module_merge(module_info, module_info) = result(module_info, string).
484492

485493
module_merge(Ma, Mb) =
486-
module_info(Ma ^ mi_name,
494+
( if Ma ^ mi_pcflags = Mb ^ mi_pcflags then
495+
ok(module_info(Ma ^ mi_name,
487496
context_earliest(Ma ^ mi_context, Mb ^ mi_context),
488497
Ma ^ mi_file,
489-
Ma ^ mi_pcflags) :-
490-
expect(unify(Ma ^ mi_pcflags, Mb ^ mi_pcflags),
491-
$module, $pred, "Flags set for module differently in different
492-
programs").
498+
Ma ^ mi_pcflags))
499+
else
500+
return_error(context_earliest(Ma ^ mi_context, Mb ^ mi_context),
501+
"Flags set for the same module in different programs do not match")
502+
).
493503

494504
:- pred find_module_file(module_info::in,
495505
result(module_info, string)::out,
496506
dir_info::in, dir_info::out, io::di, io::uo) is det.
497507

498508
find_module_file(Module, ModuleResult, !DirInfo, !IO) :-
499-
find_module_file(".", source_extension, Module ^ mi_name, FileRes, !DirInfo, !IO),
509+
find_module_file(".", source_extension, Module ^ mi_name, FileRes,
510+
!DirInfo, !IO),
500511
( FileRes = yes(File),
501512
ModuleResult = ok(Module ^ mi_file := File)
502513
; FileRes = no,

src/util.result.m

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
:- import_module io.
1717
:- import_module cord.
1818
:- import_module list.
19+
:- import_module map.
1920
:- import_module maybe.
2021

2122
:- import_module context.
@@ -97,6 +98,23 @@ func error_or_warning(E) = error_or_warning
9798

9899
:- func result_map((func(T) = U), result(T, E)) = result(U, E).
99100

101+
%-----------------------------------------------------------------------%
102+
103+
% foldl over a list except the accumulator includes a result that must
104+
% be unpact before processing the next item. If mercury had monads this
105+
% would be bind.
106+
%
107+
:- pred foldl_result(pred(X, A, result(A, E)), list(X),
108+
A, result(A, E)).
109+
:- mode foldl_result(pred(in, in, out) is det, in, in, out) is det.
110+
111+
% Set or update the value within a map at the given key. if the update
112+
% function fails then return that error.
113+
%
114+
:- pred map_set_or_update_result(func(V) = result(V, E),
115+
K, V, map(K, V), result(map(K, V), E)).
116+
:- mode map_set_or_update_result(in, in, in, in, out) is det.
117+
100118
%-----------------------------------------------------------------------%
101119

102120
:- func errors_map((func(E1) = E2), errors(E1)) = errors(E2).
@@ -205,6 +223,33 @@ func error_or_warning(E) = error_or_warning
205223

206224
%-----------------------------------------------------------------------%
207225

226+
foldl_result(_, [], Acc, ok(Acc)).
227+
foldl_result(Pred, [X | Xs], Acc0, MaybeAcc) :-
228+
Pred(X, Acc0, MaybeAcc1),
229+
( MaybeAcc1 = ok(Acc1),
230+
foldl_result(Pred, Xs, Acc1, MaybeAcc)
231+
; MaybeAcc1 = errors(Error),
232+
MaybeAcc = errors(Error)
233+
).
234+
235+
%-----------------------------------------------------------------------%
236+
237+
map_set_or_update_result(UpdateFn, Key, Value, !.Map, MaybeMap) :-
238+
( if search(!.Map, Key, Old) then
239+
MaybeNew = UpdateFn(Old),
240+
( MaybeNew = ok(New),
241+
det_update(Key, New, !Map),
242+
MaybeMap = ok(!.Map)
243+
; MaybeNew = errors(Error),
244+
MaybeMap = errors(Error)
245+
)
246+
else
247+
set(Key, Value, !Map),
248+
MaybeMap = ok(!.Map)
249+
).
250+
251+
%-----------------------------------------------------------------------%
252+
208253
errors_map(Func, Errors) = map(error_map(Func), Errors).
209254

210255
:- func error_map((func(E1) = E2), error(E1)) = error(E2).

tests/build/options_compiler_03.build

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# This is free and unencumbered software released into the public domain.
2+
# See ../LICENSE.unlicense
3+
4+
# PLZTEST type compile_failure
5+
6+
# This test asks the build system to build the same module with different
7+
# settings, it should fail.
8+
9+
[options_compiler_03a]
10+
type = program
11+
modules = [ OptionsCompiler03a, OptionsCompiler03 ]
12+
compiler_opts = "--no-simplify"
13+
14+
[options_compiler_03b]
15+
type = program
16+
modules = [ OptionsCompiler03b, OptionsCompiler03 ]
17+

tests/build/options_compiler_03.exp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
options_compiler_03.build:11: Flags set for the same module in different
2+
programs do not match

0 commit comments

Comments
 (0)