%---------------------------------------------------------------------------% % vim: ft=mercury ts=4 sw=4 et %---------------------------------------------------------------------------% % Copyright (C) 2002-2011 The University of Melbourne. % Copyright (C) 2013-2017, 2019-2025 The Mercury team. % This file may only be copied under the terms of the GNU General % Public License - see the file COPYING in the Mercury distribution. %---------------------------------------------------------------------------% % % File: make.prereqs.m. % Original author: stayl. % Author of current version: zs. % % This job of this module to find, for a given file T (a target file), % which *other* Pi (prerequisite files) you need in order to build T. % Effectively, given a file name T, it finds all the prerequisites % that occur on the right hand sides of the (implicit) make rules % whose left hand side contains T: % % T: P1 P2 ... % % Note that we find only the *direct* prereqs of T. This means that % we return e.g. P1, but not the files needed to build P1 itself. % (Unless by some unlikely chance, the files needed to build P1 % are also direct prereqs of T itself.) % % We should consider returning effectively a tree, whose nodes are file names, % where the children of a node are the direct prereqs of the file represented % by that node, but which have their own prereqs as their children, all the way % down to the files that have *no* prerequisites. We could construct such % a tree for every target named on the "mmc --make" command line, yielding % effectively a forest. % % Having the full forest available before we start building the first target % should allow us to increase parallelism by exploiting our knowledge of % the structure of Mercury dependencies. We could follow a strategy of % building files in a bottom up order, like a layercake: % % - building all needed .int3 files % - building all needed .int0 files % - building all needed .int and .int2 files % - building all needed .opt files (if enabled) % - building all needed .trans_opt files (if enabled) % - building all needed .c/.java/.cs files, depending on the target language % - building all needed .o/.jar/.dll files, depending on the target language % - building all needed executables or their equivalents % % In most of these stages, once all the files of the previous stages have been % built, it should be possible to build all files with the given suffix % in that stage in parallel. The exceptions are the creation of .int0 files % (where the creation of the .int0 files for e.g. module A and module A.B % may not be independent), and the creation of .trans_opt files (which must % respect the chosen order between those files.) % % In the absence of this global view, it is possible for e.g. an invocation % of "mmc --make -j8 prog" the decide to build A.c, B.c, C.c, D.c, E.c, F.c % and G.c at once, but if all of those modules import module H, then all % seven build processes may need to stall waiting for the completion of % the task that builds H.int. This cannot happen with the layercake approach. % % The one drawback of the layercake approach is that computing the full % prereq tree before building the first file may feel like a slow startup % to the user. This is definitely a much smaller concern now (the 2020s) % than it was in the 1980s, but whether the startup delay it causes % is below the perceptibility threshold for typical size projects, % is something that can be answered only by empirical testing. % %---------------------------------------------------------------------------% :- module make.prereqs. :- interface. :- import_module libs. :- import_module libs.globals. :- import_module make.make_info. :- import_module parse_tree. :- import_module parse_tree.module_dep_info. :- import_module io. :- import_module set. %---------------------------------------------------------------------------% :- type find_prereqs_result ---> could_not_find_some_prereqs(set(target_id)) % There were some prerequisites that we could not find. % The set specifies the prerequisites we *could* find. ; found_all_prereqs(set(target_id)). % We found all prerequisites, and here they are. % find_direct_prereqs_of_target_file(ProgressStream, Globals, % CompilationTaskType, ModuleDepInfo, TargetFile, % PrereqsResult, !Info, !IO): % % The TargetType and ModuleIndexes arguments define a set of make targets. % Return in PrereqsResult the target_id_indexes of all the files % that these make targets depend on, and which therefore have to be built % before we can build those make targets. % :- pred find_direct_prereqs_of_target_file(io.text_output_stream::in, globals::in, compilation_task_type::in, module_dep_info::in, target_file::in, find_prereqs_result::out, make_info::in, make_info::out, io::di, io::uo) is det. %---------------------------------------------------------------------------% %---------------------------------------------------------------------------% :- implementation. :- import_module backend_libs. :- import_module backend_libs.compile_target_code. :- import_module libs.file_util. :- import_module libs.maybe_util. :- import_module libs.options. :- import_module make.file_names. :- import_module make.find_local_modules. :- import_module make.get_module_dep_info. :- import_module make.index_set. :- import_module make.prereqs_cache. :- import_module make.util. :- import_module mdbcomp. :- import_module mdbcomp.sym_name. :- import_module parse_tree.file_names. :- import_module parse_tree.module_baggage. :- import_module parse_tree.prog_data_foreign. :- import_module bool. :- import_module list. :- import_module map. :- import_module sparse_bitset. :- import_module string. %---------------------------------------------------------------------------% % XXX MDNEW add loop on top to find indirect prereqs % That way, complexity is given by % #layers in dependency hierarchy * avg width of each layer % instead of by #paths through the layers, % but ONLY if we don't repeat this work later, in submakes. % % XXX MDNEW Sort the final, overall set of prereqs % - first on target type (.int3, .int0, .int/.int2, .opt etc) % - then on the list of module name components % % Sorting on target type should put prereqs before the things they are prereqs % *for* in all cases where the target types differ. % % Sorting on the list of module name components should put prereqs before % the things they are prereqs *for* in all cases where the target types match. % % For parallel makes, we would also need to return, for each element of the % list, the set of earlier elements that are its prereqs. % % XXX MDNEW We should never put any targets involving nested submodules into % sets of depenendency_file_indexes. Those targets will be made as a side % effect of making the same target type for the top module in the source file. % However, the prereqs of a nested submodule, such as any fact table files % it may need, must become the prereqs of the top-level module of their % source file. find_direct_prereqs_of_target_file(ProgressStream, Globals, CompilationTaskType, ModuleDepInfo, TargetFile, PrereqsResult, !Info, !IO) :- TargetFile = target_file(ModuleName, TargetType), ( CompilationTaskType = process_module(_), module_dep_info_get_maybe_top_module(ModuleDepInfo, MaybeTopModule), NestedSubModulesToCheck = get_nested_children_list_of_top_module(MaybeTopModule) ; ( CompilationTaskType = target_code_to_object_code(_) ; CompilationTaskType = fact_table_code_to_object_code(_, _) ), NestedSubModulesToCheck = [] ), KeepGoing = make_info_get_keep_going(!.Info), ( NestedSubModulesToCheck = [], ModulesToCheck = [ModuleName], module_name_to_index(ModuleName, ModuleIndex, !Info), find_direct_prereqs_of_module_target(ProgressStream, KeepGoing, Globals, TargetType, ModuleIndex, Succeeded, PrereqIndexes0, !Info, !IO) ; NestedSubModulesToCheck = [_ | _], ModulesToCheck = [ModuleName | NestedSubModulesToCheck], module_names_to_index_set(ModulesToCheck, ModuleIndexesToCheckSet, !Info), ModuleIndexesToCheck = index_set_to_sorted_list(ModuleIndexesToCheckSet), find_direct_prereqs_of_nested_module_targets(ProgressStream, KeepGoing, Globals, TargetType, ModuleIndexesToCheck, succeeded, Succeeded, index_set_init, PrereqIndexes0, !Info, !IO) ), ( if TargetType = module_target_int0 then % XXX Simon Taylor's comment, added originally to make.module_target.m % on 2002 Apr 23, says: % % Avoid circular dependencies (the `.int0' files for the % nested sub-modules depend on this module's `.int0' file). % % The log message of the commit says: % % The `.int0' file for a module depends on the `.int0' file for the % parent module, which caused circular dependencies with nested % submodules, resulting in a compiler abort. The circular % dependencies are now removed from the list of dependencies to make. % Test case: tests/valid/foreign_type_spec.m. % % That test case, after being moved to valid_seq, was deleted together % with the IL backend. It seems to have consisted of a main module % and a separate submodule, so the NestedSubModules part of % ModulesToCheck would have been irrelevant. And the ModuleName part % of ModulesToCheck seems to be redundant: if the *target* is % ModuleName.int0, then surely ModuleName.int0 cannot be a prereq? % % For these reasons, the code here seems to me (zs) to be too crude: % it seems to delete far more prereqs than just the ones that may % cause the problem that it was added to address. ToDelete = make_target_id_list(ModulesToCheck, module_target_int0), target_ids_to_index_set(ToDelete, ToDeleteIndexes, !Info), PrereqIndexes = index_set_difference(PrereqIndexes0, ToDeleteIndexes) else ToDelete = [], PrereqIndexes = PrereqIndexes0 ), target_id_index_set_to_plain_set(!.Info, PrereqIndexes, Prereqs), ( Succeeded = did_not_succeed, PrereqsResult = could_not_find_some_prereqs(Prereqs) ; Succeeded = succeeded, PrereqsResult = found_all_prereqs(Prereqs) ), globals.lookup_bool_option(Globals, debug_make, DebugMake), ( DebugMake = no ; DebugMake = yes, % XXX LEGACY set.map2_fold(target_id_to_file_name(Globals), Prereqs, PrereqFileNames, _PrereqFileNamesProposed, !IO), WriteFileName = ( pred(FN::in, SIO0::di, SIO::uo) is det :- io.format(ProgressStream, "\t%s\n", [s(FN)], SIO0, SIO) ), io.format(ProgressStream, "direct prereqs of %s %s:\n", [s(sym_name_to_string(ModuleName)), s(string.string(TargetType))], !IO), set.foldl(WriteFileName, PrereqFileNames, !IO), ( ToDelete = [] ; ToDelete = [_ | _], % XXX LEGACY list.map2_foldl(target_id_to_file_name(Globals), ToDelete, ToDeleteFileNames, _ToDeleteFileNamesProposed, !IO), io.write_string(ProgressStream, "after deleting:\n", !IO), list.foldl(WriteFileName, ToDeleteFileNames, !IO) ), io.write_string(ProgressStream, "end direct prereqs\n", !IO) ). :- pred find_direct_prereqs_of_nested_module_targets(io.text_output_stream::in, maybe_keep_going::in, globals::in, module_target_type::in, list(module_index)::in, maybe_succeeded::in, maybe_succeeded::out, target_id_index_set::in, target_id_index_set::out, make_info::in, make_info::out, io::di, io::uo) is det. find_direct_prereqs_of_nested_module_targets(_, _, _, _, [], !Succeeded, !Prereqs, !Info, !IO). find_direct_prereqs_of_nested_module_targets(ProgressStream, KeepGoing, Globals, TargetType, [ModuleIndex | ModuleIndexes], !Succeeded, !Prereqs, !Info, !IO) :- find_direct_prereqs_of_module_target(ProgressStream, KeepGoing, Globals, TargetType, ModuleIndex, HeadSucceeded, HeadPrereqs, !Info, !IO), index_set_union(HeadPrereqs, !Prereqs), should_we_stop_or_continue(KeepGoing, HeadSucceeded, StopOrContinue, !Succeeded), ( StopOrContinue = soc_stop ; StopOrContinue = soc_continue, find_direct_prereqs_of_nested_module_targets(ProgressStream, KeepGoing, Globals, TargetType, ModuleIndexes, !Succeeded, !Prereqs, !Info, !IO) ). :- pred find_direct_prereqs_of_module_target(io.text_output_stream::in, maybe_keep_going::in, globals::in, module_target_type::in, module_index::in, maybe_succeeded::out, target_id_index_set::out, make_info::in, make_info::out, io::di, io::uo) is det. find_direct_prereqs_of_module_target(ProgressStream, KeepGoing, Globals, TargetType, ModuleIndex, Succeeded, Prereqs, !Info, !IO) :- ( ( TargetType = module_target_source ; TargetType = module_target_track_flags ), Succeeded = succeeded, Prereqs = index_set_init ; TargetType = module_target_int3, PrereqSpecs = [self(module_target_source)], find_prereqs_from_specs(ProgressStream, KeepGoing, Globals, ModuleIndex, PrereqSpecs, Prereqs, succeeded, Succeeded, !Info, !IO) ; ( TargetType = module_target_int0 ; TargetType = module_target_int1 ; TargetType = module_target_int2 ), PrereqSpecs = [ self(module_target_source), ancestors(module_target_int0), direct_imports_intermod(module_target_int3), indirect_imports_intermod(module_target_int3) ], find_prereqs_from_specs(ProgressStream, KeepGoing, Globals, ModuleIndex, PrereqSpecs, Prereqs, succeeded, Succeeded, !Info, !IO) ; ( TargetType = module_target_c_code ; TargetType = module_target_c_header(_) ; TargetType = module_target_csharp_code ; TargetType = module_target_java_code ; TargetType = module_target_errors ), compiled_code_dependencies(Globals, PrereqSpecs), % XXX MDNEW Get intermod, pass as extra arg in the returned deps. % XXX MDNEW Same for direct and indirect deps, and ancestors. find_prereqs_from_specs(ProgressStream, KeepGoing, Globals, ModuleIndex, PrereqSpecs, Prereqs, succeeded, Succeeded, !Info, !IO) ; TargetType = module_target_java_class_code, % Generating the .class file of a module obviously requires % its .java file. However, it also seems to need the .java files % of the modules it imports, directly or indirectly. % % For modules in other directories, such as standard library modules, % we don't need to make them now, since they have been made by % mmc --make invocations in those other directories. % For the modules in the current directory, we want to make them now. % This extra set of prerequisites fixes a whole bunch of test case % failures in tests/{valid,valid_seq} in the java grade. % % XXX I (zs) don't know whether doing s/non_intermod/intermod/ on % the specifications below would prevent any more test case failures. % This is because for me the difference is moot, due to java bootchecks % being slow enough that I don't usually do them with intermodule % optimization enabled. % % NOTE When making executables or libraries in a java grade, % make.program_target.m does NOT make the program's .class files % one-by-one using this target. Instead, it gives all the .java files % that do not have an up-to-date corresponding .class file to the % Java compiler all in one invocation. The reason for this is that % the Java compiler will generate .class code not just for the % .java files on its command line, but also for any other reachable % .java files that define classes that the command-line files refer to % but do not define. This means that compiling the .java files % of the program separately, one-by-one, could, about probably would, % recompile many .java files many times. PrereqSpecs = [ self(module_target_java_code), direct_imports_non_intermod_local(module_target_java_code), indirect_imports_non_intermod_local(module_target_java_code) ], find_prereqs_from_specs(ProgressStream, KeepGoing, Globals, ModuleIndex, PrereqSpecs, Prereqs, succeeded, Succeeded, !Info, !IO) ; TargetType = module_target_fact_table_object(PIC, _), globals.get_target(Globals, CompilationTarget), TargetCodeType = target_to_module_target_code(CompilationTarget, PIC), PrereqSpec = self(TargetCodeType), find_prereqs_from_spec(ProgressStream, KeepGoing, Globals, ModuleIndex, PrereqSpec, Succeeded, Prereqs, !Info, !IO) ; TargetType = module_target_object_code(PIC), globals.get_target(Globals, CompilationTarget), TargetCodeType = target_to_module_target_code(CompilationTarget, PIC), globals.lookup_bool_option(Globals, highlevel_code, HighLevelCode), MhHeader = module_target_c_header(header_mh), MihHeader = module_target_c_header(header_mih), PrereqSpecSelf = self(TargetCodeType), PrereqSpecMh = foreign_imports_intermod_trans(MhHeader), ( if CompilationTarget = target_c, HighLevelCode = yes then PrereqSpecs = [PrereqSpecSelf, PrereqSpecMh, direct_imports_intermod(MihHeader), indirect_imports_intermod(MihHeader), ancestors(MihHeader), intermod_imports(MihHeader) ] else PrereqSpecs = [PrereqSpecSelf, PrereqSpecMh] ), find_prereqs_from_specs(ProgressStream, KeepGoing, Globals, ModuleIndex, PrereqSpecs, Prereqs, succeeded, Succeeded, !Info, !IO) ; ( TargetType = module_target_opt ; TargetType = module_target_xml_doc ), PrereqSpecs = [ self(module_target_source), anc0_dir1_indir2_non_intermod ], find_prereqs_from_specs(ProgressStream, KeepGoing, Globals, ModuleIndex, PrereqSpecs, Prereqs, succeeded, Succeeded, !Info, !IO) ; TargetType = module_target_analysis_registry, PrereqSpecs = [ self(module_target_source), anc0_dir1_indir2_non_intermod, direct_imports_intermod(module_target_opt), indirect_imports_intermod(module_target_opt), intermod_imports(module_target_opt) ], find_prereqs_from_specs(ProgressStream, KeepGoing, Globals, ModuleIndex, PrereqSpecs, Prereqs, succeeded, Succeeded, !Info, !IO) ). :- func target_to_module_target_code(compilation_target, pic) = module_target_type. target_to_module_target_code(_CompilationTarget, _PIC) = TargetCode :- % XXX it looks wrong to be returning module_target_c_code for % all compilation targets. TargetCode = module_target_c_code. :- pred compiled_code_dependencies(globals::in, list(prereq_spec)::out) is det. compiled_code_dependencies(Globals, PrereqSpecs) :- % We build up PrereqSpecs in stages. % Stage 0: dependencies on flags. globals.lookup_bool_option(Globals, make_track_flags, TrackFlags), ( TrackFlags = yes, PrereqSpecsTracks = [self(module_target_track_flags)] ; TrackFlags = no, PrereqSpecsTracks = [] ), % Stage 1: dependencies on the source file, and on the fact table files, % foreign language files and Mercury interface files it imports. PrereqSpecsSrcInts = [ self(module_target_source), self_foreign_incl_fact_table_files, self(module_target_int1), % XXX MDNEW The next two prereq_specs should be a single % combined prereq_spec, anc01_dir1_indir2_intermod. ancestors(module_target_int1), anc0_dir1_indir2_intermod ], globals.lookup_bool_option(Globals, intermodule_optimization, IntermodOpt), globals.lookup_bool_option(Globals, intermodule_analysis, IntermodAnalysis), AnyIntermod = bool.or(IntermodOpt, IntermodAnalysis), % Stage 2: dependencies on optimization files. ( AnyIntermod = yes, PrereqSpecsOpts = [ self(module_target_opt), % XXX MDNEW Given that we compute the set of intermod imports % for this prereq_spec ... intermod_imports(module_target_opt), % ... why do we have to compute it AGAIN, as part of this % prereq_spec as well? % % We should replace both of these prereq_specs with one that % does the job of both but computes the set of intermod_imports % modules set just once. This would save even the cost of a % cache hit. anc0_dir1_indir2_intermod_of_ancestors_of_intermod_imports ] ; AnyIntermod = no, PrereqSpecsOpts = [] ), % Stage 3: dependencies on analysis result files. ( IntermodAnalysis = yes, PrereqSpecsRegistries = [ self(module_target_analysis_registry), direct_imports_intermod(module_target_analysis_registry) ] ; IntermodAnalysis = no, PrereqSpecsRegistries = [] ), PrereqSpecs = PrereqSpecsTracks ++ PrereqSpecsSrcInts ++ PrereqSpecsOpts ++ PrereqSpecsRegistries. %---------------------------------------------------------------------------% % The prerequisite specification type. % % Values of this type indirectly represent the specification of % a set of target_ids (actually, target_id_indexes). % The "indirect" part is there because they actually represent % a specification of a task for find_prereqs_from_spec, which will compute % that set of target_id_indexes when given a prereq_spec. % % NOTE I (zs) considered using a local_modules_only wrapper around % a prereq_spec to replace {direct,indirect}_imports_non_intermod_local, % but this turns out to be a bad idea for two reasons. % % - First, the local-modules-only filter must be applied *between* % determining a set of maybe-local-or-maybe-not modules, and % converting the local module names' indexes to target_ids by adding % a target_type, which means that applying the filter *after* having % find_prereqs_from_spec return a target_id_index_set requires % first effectively converting each target_id_index back to % a module_index. % % - Second, one of the prereq_specs, self_foreign_incl_fact_table_files, % specifies target_ids that do not *have* a module name component, % and such targets therefore cannot reasonably be considered as % either having, or not having, a local Mercury source module. % :- type prereq_spec ---> self(module_target_type) ; ancestors(module_target_type) ; direct_imports_non_intermod_local(module_target_type) ; direct_imports_non_intermod(module_target_type) ; direct_imports_intermod(module_target_type) ; indirect_imports_non_intermod_local(module_target_type) ; indirect_imports_non_intermod(module_target_type) ; indirect_imports_intermod(module_target_type) ; intermod_imports(module_target_type) ; foreign_imports_intermod_trans(module_target_type) ; anc0_dir1_indir2_non_intermod ; anc0_dir1_indir2_intermod % Get the .int0 files of ancestors, the .int files of direct % imports, and the .int2 files of indirect imports. ; anc0_dir1_indir2_intermod_of_ancestors_of_intermod_imports % Get the .int0 files of ancestors, the .int files of direct % imports, and the .int2 files of indirect imports, but not % of the specified module, but of the ancestors of its intermod % imports. ; self_foreign_incl_fact_table_files. % Files named in foreign include module and fact table pragmas. :- pred find_prereqs_from_specs(io.text_output_stream::in, maybe_keep_going::in, globals::in, module_index::in, list(prereq_spec)::in, target_id_index_set::out, maybe_succeeded::in, maybe_succeeded::out, make_info::in, make_info::out, io::di, io::uo) is det. find_prereqs_from_specs(_, _, _, _, [], index_set_init, !Succeeded, !Info, !IO). find_prereqs_from_specs(ProgressStream, KeepGoing, Globals, ModuleIndex, [HeadPrereqSpec | TailPrereqSpecs], TargetIdIndexSet, !Succeeded, !Info, !IO) :- find_prereqs_from_spec(ProgressStream, KeepGoing, Globals, ModuleIndex, HeadPrereqSpec, HeadSucceeded, HeadTargetIdIndexSet, !Info, !IO), should_we_stop_or_continue(KeepGoing, HeadSucceeded, StopOrContinue, !Succeeded), ( StopOrContinue = soc_stop, TargetIdIndexSet = HeadTargetIdIndexSet ; StopOrContinue = soc_continue, find_prereqs_from_specs(ProgressStream, KeepGoing, Globals, ModuleIndex, TailPrereqSpecs, TailTargetIdIndexSet, !Succeeded, !Info, !IO), index_set_union(HeadTargetIdIndexSet, TailTargetIdIndexSet, TargetIdIndexSet) ). :- pred find_prereqs_from_spec(io.text_output_stream::in, maybe_keep_going::in, globals::in, module_index::in, prereq_spec::in, maybe_succeeded::out, target_id_index_set::out, make_info::in, make_info::out, io::di, io::uo) is det. find_prereqs_from_spec(ProgressStream, KeepGoing, Globals, ModuleIndex, PrereqSpec, Succeeded, TargetIdIndexSet, !Info, !IO) :- trace [ compile_time(flag("find_prereqs_from_spec")), run_time(env("FIND_PREREQS_FROM_SPEC")), io(!TIO) ] ( module_index_to_name(!.Info, ModuleIndex, IndexModuleName), IndexModuleNameStr = sym_name_to_string(IndexModuleName), io.format(ProgressStream, "starting prereq_spec %s for %s\n", [s(string.string(PrereqSpec)), s(IndexModuleNameStr)], !TIO) ), % XXX Some of these alternatives don't need I/O. % We can wrap caching code around the code of any set of switch arms. % % XXX Are there are any prereq_spec kinds for which we may return % did_not_succeed AND a nonempty TargetIdIndexSet? If not, then % those two parameters are effectively a single value of a maybe type. ( PrereqSpec = self(TargetType), Succeeded = succeeded, timi_target(ModuleIndex, TargetType, TargetIdIndexSet, !Info) ; PrereqSpec = ancestors(TargetType), Succeeded = succeeded, module_index_to_name(!.Info, ModuleIndex, ModuleName), Ancestors = get_ancestors(ModuleName), module_names_to_index_set(Ancestors, ModuleIndexSet, !Info), timi_targets(ModuleIndexSet, TargetType, TargetIdIndexSet, !Info) ; PrereqSpec = direct_imports_non_intermod_local(TargetType), get_direct_imports_non_intermod(ProgressStream, KeepGoing, Globals, ModuleIndex, Succeeded, ModuleIndexSet0, !Info, !IO), ModuleIndexes0 = index_set_to_sorted_list(ModuleIndexSet0), find_local_modules(ProgressStream, ModuleIndexes0, index_set_init, ModuleIndexSet, !Info, !IO), timi_targets(ModuleIndexSet, TargetType, TargetIdIndexSet, !Info) ; PrereqSpec = direct_imports_non_intermod(TargetType), get_direct_imports_non_intermod(ProgressStream, KeepGoing, Globals, ModuleIndex, Succeeded, ModuleIndexSet, !Info, !IO), timi_targets(ModuleIndexSet, TargetType, TargetIdIndexSet, !Info) ; PrereqSpec = direct_imports_intermod(TargetType), get_direct_imports_intermod(ProgressStream, KeepGoing, Globals, ModuleIndex, Succeeded, ModuleIndexSet, !Info, !IO), timi_targets(ModuleIndexSet, TargetType, TargetIdIndexSet, !Info) ; PrereqSpec = indirect_imports_non_intermod_local(TargetType), get_indirect_imports_non_intermod(ProgressStream, KeepGoing, Globals, ModuleIndex, Succeeded, ModuleIndexSet0, !Info, !IO), ModuleIndexes0 = index_set_to_sorted_list(ModuleIndexSet0), find_local_modules(ProgressStream, ModuleIndexes0, index_set_init, ModuleIndexSet, !Info, !IO), timi_targets(ModuleIndexSet, TargetType, TargetIdIndexSet, !Info) ; PrereqSpec = indirect_imports_non_intermod(TargetType), get_indirect_imports_non_intermod(ProgressStream, KeepGoing, Globals, ModuleIndex, Succeeded, ModuleIndexSet, !Info, !IO), timi_targets(ModuleIndexSet, TargetType, TargetIdIndexSet, !Info) ; PrereqSpec = indirect_imports_intermod(TargetType), get_indirect_imports_intermod(ProgressStream, KeepGoing, Globals, ModuleIndex, Succeeded, ModuleIndexSet, !Info, !IO), timi_targets(ModuleIndexSet, TargetType, TargetIdIndexSet, !Info) ; PrereqSpec = intermod_imports(TargetType), get_intermod_imports(ProgressStream, KeepGoing, Globals, ModuleIndex, Succeeded, ModuleIndexSet, !Info, !IO), timi_targets(ModuleIndexSet, TargetType, TargetIdIndexSet, !Info) ; PrereqSpec = foreign_imports_intermod_trans(TargetType), get_foreign_imports_intermod_trans(ProgressStream, KeepGoing, Globals, ModuleIndex, Succeeded, ModuleIndexSet, !Info, !IO), timi_targets(ModuleIndexSet, TargetType, TargetIdIndexSet, !Info) ; PrereqSpec = anc0_dir1_indir2_non_intermod, SubPrereqSpecs = [ ancestors(module_target_int0), direct_imports_non_intermod(module_target_int1), indirect_imports_non_intermod(module_target_int2) ], trace [ compile_time(flag("find_prereqs_from_spec")), run_time(env("FIND_PREREQS_FROM_SPEC")), io(!TIO) ] ( module_index_to_name(!.Info, ModuleIndex, IndexModuleName), IndexModuleNameStr = sym_name_to_string(IndexModuleName), io.format(ProgressStream, "prereq_spec %s for %s starts\n\n", [s(string.string(PrereqSpec)), s(IndexModuleNameStr)], !TIO) ), % This cache is disabled, because it is ineffective. % ( if % search_anc0_dir1_indir2_non_intermod_cache(!.Info, ModuleIndex, % Result0) % then % Result0 = deps_result(Succeeded, TargetIdIndexSet) % else find_prereqs_from_specs(ProgressStream, KeepGoing, Globals, ModuleIndex, SubPrereqSpecs, TargetIdIndexSet, succeeded, Succeeded, !Info, !IO), % Result = deps_result(Succeeded, TargetIdIndexSet), % add_to_anc0_dir1_indir2_non_intermod_cache(ModuleIndex, Result, % !Info) % ), trace [ compile_time(flag("find_prereqs_from_spec")), run_time(env("FIND_PREREQS_FROM_SPEC")), io(!TIO) ] ( module_index_to_name(!.Info, ModuleIndex, IndexModuleName), IndexModuleNameStr = sym_name_to_string(IndexModuleName), io.format(ProgressStream, "prereq_spec %s for %s ends\n", [s(string.string(PrereqSpec)), s(IndexModuleNameStr)], !TIO) ) ; PrereqSpec = anc0_dir1_indir2_intermod, SubPrereqSpecs = [ ancestors(module_target_int0), direct_imports_intermod(module_target_int1), indirect_imports_intermod(module_target_int2) ], trace [ compile_time(flag("find_prereqs_from_spec")), run_time(env("FIND_PREREQS_FROM_SPEC")), io(!TIO) ] ( module_index_to_name(!.Info, ModuleIndex, IndexModuleName), IndexModuleNameStr = sym_name_to_string(IndexModuleName), io.format(ProgressStream, "prereq_spec %s for %s starts\n\n", [s(string.string(PrereqSpec)), s(IndexModuleNameStr)], !TIO) ), ( if search_anc0_dir1_indir2_intermod_cache(!.Info, ModuleIndex, Result0) then Result0 = prereqs_result(Succeeded, TargetIdIndexSet) else find_prereqs_from_specs(ProgressStream, KeepGoing, Globals, ModuleIndex, SubPrereqSpecs, TargetIdIndexSet, succeeded, Succeeded, !Info, !IO), Result = prereqs_result(Succeeded, TargetIdIndexSet), add_to_anc0_dir1_indir2_intermod_cache(ModuleIndex, Result, !Info) ), trace [ compile_time(flag("find_prereqs_from_spec")), run_time(env("FIND_PREREQS_FROM_SPEC")), io(!TIO) ] ( module_index_to_name(!.Info, ModuleIndex, IndexModuleName), IndexModuleNameStr = sym_name_to_string(IndexModuleName), io.format(ProgressStream, "prereq_spec %s for %s ends\n", [s(string.string(PrereqSpec)), s(IndexModuleNameStr)], !TIO) ) ; PrereqSpec = anc0_dir1_indir2_intermod_of_ancestors_of_intermod_imports, trace [ compile_time(flag("find_prereqs_from_spec")), run_time(env("FIND_PREREQS_FROM_SPEC")), io(!TIO) ] ( module_index_to_name(!.Info, ModuleIndex, IndexModuleName), IndexModuleNameStr = sym_name_to_string(IndexModuleName), io.format(ProgressStream, "prereq_spec %s for %s starts\n\n", [s(string.string(PrereqSpec)), s(IndexModuleNameStr)], !TIO) ), get_anc0_dir1_indir2_intermod_of_ancestors_of_intermod_imports( ProgressStream, KeepGoing, Globals, ModuleIndex, Succeeded, TargetIdIndexSet, !Info, !IO), trace [ compile_time(flag("find_prereqs_from_spec")), run_time(env("FIND_PREREQS_FROM_SPEC")), io(!TIO) ] ( module_index_to_name(!.Info, ModuleIndex, IndexModuleName), IndexModuleNameStr = sym_name_to_string(IndexModuleName), io.format(ProgressStream, "prereq_spec %s for %s ends\n", [s(string.string(PrereqSpec)), s(IndexModuleNameStr)], !TIO) ) ; PrereqSpec = self_foreign_incl_fact_table_files, get_foreign_incl_fact_table_files(ProgressStream, Globals, ModuleIndex, Succeeded, TargetIdIndexSet, !Info, !IO) ), trace [ compile_time(flag("find_prereqs_from_spec")), run_time(env("FIND_PREREQS_FROM_SPEC")), io(!TIO) ] ( module_index_to_name(!.Info, ModuleIndex, IndexModuleName), IndexModuleNameStr = sym_name_to_string(IndexModuleName), target_id_index_set_to_plain_set(!.Info, TargetIdIndexSet, TargetIdSet), TargetIds = set.to_sorted_list(TargetIdSet), ( TargetIds = [], io.format(ProgressStream, "prereq_spec %s for %s yields no prereqs\n\n", [s(string.string(PrereqSpec)), s(IndexModuleNameStr)], !TIO) ; TargetIds = [_ | _], TargetIdNlStrs = list.map( target_id_to_debug_string(" ", "\n"), TargetIds), io.format(ProgressStream, "prereq_spec %s for %s yields these prereqs:\n", [s(string.string(PrereqSpec)), s(IndexModuleNameStr)], !TIO), list.foldl(io.write_string(ProgressStream), TargetIdNlStrs, !TIO), io.write_string(ProgressStream, "prereq list ends\n\n", !TIO) ) ). %---------------------------------------------------------------------------% :- pred timi_target(module_index::in, module_target_type::in, target_id_index_set::out, make_info::in, make_info::out) is det. :- pragma inline(pred(timi_target/5)). timi_target(ModuleIndex, TargetType, TargetIdIndexSet, !Info) :- acc_rev_timi_target(TargetType, ModuleIndex, index_set_init, TargetIdIndexSet, !Info). :- pred timi_targets(module_index_set::in, module_target_type::in, target_id_index_set::out, make_info::in, make_info::out) is det. :- pragma inline(pred(timi_targets/5)). timi_targets(ModuleIndexSet, TargetType, TargetIdIndexSet, !Info) :- index_set_foldl2(acc_rev_timi_target(TargetType), ModuleIndexSet, index_set_init, TargetIdIndexSet, !Info). :- pred acc_rev_timi_target(module_target_type::in, module_index::in, target_id_index_set::in, target_id_index_set::out, make_info::in, make_info::out) is det. :- pragma inline(pred(acc_rev_timi_target/6)). acc_rev_timi_target(TargetType, ModuleIndex, !TargetIdIndexSet, !Info) :- TargetId = timi_merc(ModuleIndex, TargetType), target_id_to_index(TargetId, TargetIdIndex, !Info), index_set_insert(TargetIdIndex, !TargetIdIndexSet). %---------------------------------------------------------------------------% % Return the modules for which `.int' files are read in a compilation % which does not use `--intermodule-optimization'. % :- pred get_direct_imports_non_intermod(io.text_output_stream::in, maybe_keep_going::in, globals::in, module_index::in, maybe_succeeded::out, module_index_set::out, make_info::in, make_info::out, io::di, io::uo) is det. get_direct_imports_non_intermod(ProgressStream, KeepGoing, Globals, ModuleIndex, Succeeded, Modules, !Info, !IO) :- ( if search_direct_imports_non_intermod_cache(!.Info, ModuleIndex, Result0) then Result0 = prereqs_result(Succeeded, Modules) else get_direct_imports_non_intermod_uncached(ProgressStream, KeepGoing, Globals, ModuleIndex, Succeeded, Modules, !Info, !IO), Result = prereqs_result(Succeeded, Modules), add_to_direct_imports_non_intermod_cache(ModuleIndex, Result, !Info) ). :- pred get_direct_imports_non_intermod_uncached(io.text_output_stream::in, maybe_keep_going::in, globals::in, module_index::in, maybe_succeeded::out, module_index_set::out, make_info::in, make_info::out, io::di, io::uo) is det. get_direct_imports_non_intermod_uncached(ProgressStream, KeepGoing, Globals, ModuleIndex, Succeeded, Modules, !Info, !IO) :- module_index_to_name(!.Info, ModuleIndex, ModuleName), get_maybe_module_dep_info(ProgressStream, Globals, ModuleName, MaybeModuleDepInfo, !Info, !IO), ( MaybeModuleDepInfo = some_module_dep_info(ModuleDepInfo), % Find the direct imports of this module, i.e. the modules % for which we will read the `.int' files. % % Note that we need to do this both for the imports of this module, % and for the imports of its ancestors. This is because if this module % is a submodule, then it may depend on things imported only by its % ancestors. % module_dep_info_get_int_deps(ModuleDepInfo, IntModuleNames), module_dep_info_get_imp_deps(ModuleDepInfo, ImpModuleNames), module_names_to_index_set(set.to_sorted_list(IntModuleNames), IntModules, !Info), module_names_to_index_set(set.to_sorted_list(ImpModuleNames), ImpModules, !Info), index_set_union(IntModules, ImpModules, Modules0), ( ModuleName = qualified(ParentModule, _), module_name_to_index(ParentModule, ParentIndex, !Info), get_direct_imports_non_intermod(ProgressStream, KeepGoing, Globals, ParentIndex, Succeeded, ParentImports, !Info, !IO), index_set_union(ParentImports, Modules0, Modules) ; ModuleName = unqualified(_), Succeeded = succeeded, Modules = Modules0 ) ; MaybeModuleDepInfo = no_module_dep_info, Succeeded = did_not_succeed, Modules = index_set_init ). :- pred get_direct_imports_intermod(io.text_output_stream::in, maybe_keep_going::in, globals::in, module_index::in, maybe_succeeded::out, module_index_set::out, make_info::in, make_info::out, io::di, io::uo) is det. get_direct_imports_intermod(ProgressStream, KeepGoing, Globals, ModuleIndex, Succeeded, Modules, !Info, !IO) :- ( if search_direct_imports_intermod_cache(!.Info, ModuleIndex, Result0) then Result0 = prereqs_result(Succeeded, Modules) else get_direct_imports_non_intermod(ProgressStream, KeepGoing, Globals, ModuleIndex, Succeeded0, Modules0, !Info, !IO), ( if Succeeded0 = did_not_succeed, KeepGoing = do_not_keep_going then Succeeded = did_not_succeed, Modules = index_set_init else % We also read `.int' files for the modules for which we read % `.opt' files, and for the modules imported by those modules. get_intermod_imports(ProgressStream, KeepGoing, Globals, ModuleIndex, Succeeded1, IntermodModules, !Info, !IO), ( if Succeeded1 = did_not_succeed, KeepGoing = do_not_keep_going then Succeeded = did_not_succeed, Modules = index_set_init else index_set_union(IntermodModules, Modules0, Modules1), fold_find_modules_over_modules(ProgressStream, KeepGoing, Globals, get_direct_imports_non_intermod, index_set_to_sorted_list(IntermodModules), succeeded, Succeeded2, Modules1, Modules2, !Info, !IO), Succeeded = Succeeded0 `and` Succeeded1 `and` Succeeded2, index_set_delete(ModuleIndex, Modules2, Modules) ) ), Result = prereqs_result(Succeeded, Modules), add_to_direct_imports_intermod_cache(ModuleIndex, Result, !Info) ). %---------------------------------------------------------------------------% % Return the list of modules for which we should read `.int2' files, % ignoring those which need to be read as a result of importing modules % imported by a `.opt' file. % :- pred get_indirect_imports_non_intermod(io.text_output_stream::in, maybe_keep_going::in, globals::in, module_index::in, maybe_succeeded::out, module_index_set::out, make_info::in, make_info::out, io::di, io::uo) is det. get_indirect_imports_non_intermod(ProgressStream, KeepGoing, Globals, ModuleIndex, Succeeded, IndirectNonIntermodImportModules, !Info, !IO) :- % This cache is disabled, because it is ineffective. % ( if % search_indirect_imports_non_intermod_cache(!.Info, ModuleIndex, % Result0) % then % Result0 = deps_result(Succeeded, IndirectNonIntermodImportModules) % else get_direct_imports_non_intermod(ProgressStream, KeepGoing, Globals, ModuleIndex, DirectSucceeded, DirectImportModules, !Info, !IO), get_indirect_imports_uncached(ProgressStream, KeepGoing, Globals, ModuleIndex, DirectSucceeded, DirectImportModules, Succeeded, IndirectNonIntermodImportModules, !Info, !IO). % Result = deps_result(Succeeded, IndirectNonIntermodImportModules), % add_to_indirect_imports_non_intermod_cache(ModuleIndex, Result, !Info) % ). % Return the list of modules for which we should read `.int2' files. % :- pred get_indirect_imports_intermod(io.text_output_stream::in, maybe_keep_going::in, globals::in, module_index::in, maybe_succeeded::out, module_index_set::out, make_info::in, make_info::out, io::di, io::uo) is det. get_indirect_imports_intermod(ProgressStream, KeepGoing, Globals, ModuleIndex, Succeeded, IndirectIntermodImportModules, !Info, !IO) :- ( if search_indirect_imports_intermod_cache(!.Info, ModuleIndex, Result0) then Result0 = prereqs_result(Succeeded, IndirectIntermodImportModules) else get_direct_imports_intermod(ProgressStream, KeepGoing, Globals, ModuleIndex, DirectSucceeded, DirectImportModules, !Info, !IO), get_indirect_imports_uncached(ProgressStream, KeepGoing, Globals, ModuleIndex, DirectSucceeded, DirectImportModules, Succeeded, IndirectIntermodImportModules, !Info, !IO), Result = prereqs_result(Succeeded, IndirectIntermodImportModules), add_to_indirect_imports_intermod_cache(ModuleIndex, Result, !Info) ). :- pred get_indirect_imports_uncached(io.text_output_stream::in, maybe_keep_going::in, globals::in, module_index::in, maybe_succeeded::in, module_index_set::in, maybe_succeeded::out, module_index_set::out, make_info::in, make_info::out, io::di, io::uo) is det. get_indirect_imports_uncached(ProgressStream, KeepGoing, Globals, ModuleIndex, DirectSucceeded, DirectImports, Succeeded, IndirectImports, !Info, !IO) :- ( if DirectSucceeded = did_not_succeed, KeepGoing = do_not_keep_going then Succeeded = did_not_succeed, IndirectImports = index_set_init else fold_find_modules_over_modules(ProgressStream, KeepGoing, Globals, find_transitive_implementation_imports, index_set_to_sorted_list(DirectImports), succeeded, IndirectSucceeded, index_set_init, IndirectImports0, !Info, !IO), index_set_delete(ModuleIndex, IndirectImports0, IndirectImports1), IndirectImports = index_set_difference(IndirectImports1, DirectImports), Succeeded = DirectSucceeded `and` IndirectSucceeded ). %---------------------------------------------------------------------------% % Return the list of modules for which we should read `.opt' files. % :- pred get_intermod_imports(io.text_output_stream::in, maybe_keep_going::in, globals::in, module_index::in, maybe_succeeded::out, module_index_set::out, make_info::in, make_info::out, io::di, io::uo) is det. get_intermod_imports(ProgressStream, KeepGoing, Globals, ModuleIndex, Succeeded, Modules, !Info, !IO) :- globals.get_any_intermod(Globals, AnyIntermod), ( AnyIntermod = yes, globals.lookup_bool_option(Globals, read_opt_files_transitively, Transitive), ( Transitive = yes, find_transitive_implementation_imports(ProgressStream, KeepGoing, Globals, ModuleIndex, Succeeded, Modules, !Info, !IO) ; Transitive = no, get_direct_imports_non_intermod(ProgressStream, KeepGoing, Globals, ModuleIndex, Succeeded, Modules, !Info, !IO) ) ; AnyIntermod = no, Succeeded = succeeded, Modules = index_set_init ). %---------------------------------------------------------------------------% :- pred get_foreign_imports_intermod_trans(io.text_output_stream::in, maybe_keep_going::in, globals::in, module_index::in, maybe_succeeded::out, module_index_set::out, make_info::in, make_info::out, io::di, io::uo) is det. get_foreign_imports_intermod_trans(ProgressStream, KeepGoing, Globals, ModuleIndex, Succeeded, Modules, !Info, !IO) :- % The object file depends on the header files for the modules % mentioned in `:- pragma foreign_import_module' declarations % in the current module and the `.opt' files it imports. globals.get_backend_foreign_languages(Globals, Languages), LanguagesSet = set.list_to_set(Languages), get_intermod_imports(ProgressStream, KeepGoing, Globals, ModuleIndex, IntermodSucceeded, IntermodModules, !Info, !IO), index_set_insert(ModuleIndex, IntermodModules, IntermodSelfModules), fold_find_modules_over_modules(ProgressStream, KeepGoing, Globals, get_foreign_imports_non_intermod_trans(LanguagesSet), to_sorted_list(IntermodSelfModules), succeeded, ForeignSucceeded, index_set_init, Modules, !Info, !IO), Succeeded = IntermodSucceeded `and` ForeignSucceeded. :- pred get_foreign_imports_non_intermod_trans(set(foreign_language)::in, io.text_output_stream::in, maybe_keep_going::in, globals::in, module_index::in, maybe_succeeded::out, module_index_set::out, make_info::in, make_info::out, io::di, io::uo) is det. get_foreign_imports_non_intermod_trans(LangSet, ProgressStream, KeepGoing, Globals, ModuleIndex, Succeeded, ForeignModules, !Info, !IO) :- % LangSet should be constant for the duration of the process, % which means that it is unnecessary to include it in the cache key. ( if search_foreign_imports_non_intermod_trans_cache(!.Info, ModuleIndex, Result0) then Result0 = prereqs_result(Succeeded, ForeignModules) else find_transitive_implementation_imports(ProgressStream, KeepGoing, Globals, ModuleIndex, Succeeded0, ImportedModules, !Info, !IO), ( Succeeded0 = succeeded, fold_find_modules_over_modules(ProgressStream, KeepGoing, Globals, get_foreign_imports_non_intermod_uncached(LangSet), to_sorted_list(insert(ImportedModules, ModuleIndex)), succeeded, Succeeded, index_set_init, ForeignModules, !Info, !IO), Result = prereqs_result(Succeeded, ForeignModules), add_to_foreign_imports_non_intermod_trans_cache(ModuleIndex, Result, !Info) ; Succeeded0 = did_not_succeed, Succeeded = did_not_succeed, ForeignModules = index_set_init ) ). :- pred get_foreign_imports_non_intermod_uncached(set(foreign_language)::in, io.text_output_stream::in, maybe_keep_going::in, globals::in, module_index::in, maybe_succeeded::out, module_index_set::out, make_info::in, make_info::out, io::di, io::uo) is det. get_foreign_imports_non_intermod_uncached(LangSet, ProgressStream, _KeepGoing, Globals, ModuleIndex, Succeeded, ForeignModules, !Info, !IO) :- module_index_to_name(!.Info, ModuleIndex, ModuleName), get_maybe_module_dep_info(ProgressStream, Globals, ModuleName, MaybeModuleDepInfo, !Info, !IO), ( MaybeModuleDepInfo = some_module_dep_info(ModuleDepInfo), module_dep_info_get_fims(ModuleDepInfo, FIMSpecs), set.foldl2(acc_module_index_if_for_lang_in_set(LangSet), FIMSpecs, index_set_init, ForeignModules, !Info), Succeeded = succeeded ; MaybeModuleDepInfo = no_module_dep_info, ForeignModules = index_set_init, Succeeded = did_not_succeed ). :- pred acc_module_index_if_for_lang_in_set(set(foreign_language)::in, fim_spec::in, module_index_set::in, module_index_set::out, make_info::in, make_info::out) is det. acc_module_index_if_for_lang_in_set(LangSet, FIMSpec, !ModuleIndexSet, !Info) :- FIMSpec = fim_spec(Lang, ModuleName), ( if set.contains(LangSet, Lang) then module_name_to_index(ModuleName, ModuleIndex, !Info), index_set_insert(ModuleIndex, !ModuleIndexSet) else true ). %---------------------------------------------------------------------------% :- pred get_anc0_dir1_indir2_intermod_of_ancestors_of_intermod_imports( io.text_output_stream::in, maybe_keep_going::in, globals::in, module_index::in, maybe_succeeded::out, target_id_index_set::out, make_info::in, make_info::out, io::di, io::uo) is det. get_anc0_dir1_indir2_intermod_of_ancestors_of_intermod_imports(ProgressStream, KeepGoing, Globals, ModuleIndex, !:Succeeded, TargetIdIndexSet, !Info, !IO) :- get_ancestors_of_intermod_imports(ProgressStream, KeepGoing, Globals, ModuleIndex, Succeeded1, Modules1, !Info, !IO), should_we_stop_or_continue(KeepGoing, Succeeded1, StopOrContinue, succeeded, !:Succeeded), ( StopOrContinue = soc_stop, TargetIdIndexSet = index_set_init ; StopOrContinue = soc_continue, ModuleList1 = index_set_to_sorted_list(Modules1), fold_prereq_spec_over_modules(ProgressStream, KeepGoing, Globals, anc0_dir1_indir2_intermod, ModuleList1, !Succeeded, index_set_init, TargetIdIndexSet, !Info, !IO) ). :- pred get_ancestors_of_intermod_imports(io.text_output_stream::in, maybe_keep_going::in, globals::in, module_index::in, maybe_succeeded::out, module_index_set::out, make_info::in, make_info::out, io::di, io::uo) is det. get_ancestors_of_intermod_imports(ProgressStream, KeepGoing, Globals, ModuleIndex, Succeeded, ModuleIndexSet, !Info, !IO) :- get_intermod_imports(ProgressStream, KeepGoing, Globals, ModuleIndex, Succeeded1, Modules1, !Info, !IO), should_we_stop_or_continue(KeepGoing, Succeeded1, StopOrContinue, succeeded, Succeeded), ( StopOrContinue = soc_stop, ModuleIndexSet = index_set_init ; StopOrContinue = soc_continue, ModuleList1 = index_set_to_sorted_list(Modules1), list.map_foldl(index_get_ancestors, ModuleList1, AncestorModuleIndexSets, !Info), ModuleIndexSet = index_set_union_list(AncestorModuleIndexSets) ). :- pred index_get_ancestors(module_index::in, module_index_set::out, make_info::in, make_info::out) is det. index_get_ancestors(ModuleIndex, AncestorModuleIndexSet, !Info) :- module_index_to_name(!.Info, ModuleIndex, ModuleName), AncestorModuleNames = get_ancestors(ModuleName), module_names_to_index_set(AncestorModuleNames, AncestorModuleIndexSet, !Info). %---------------------------------------------------------------------------% :- pred get_foreign_incl_fact_table_files(io.text_output_stream::in, globals::in, module_index::in, maybe_succeeded::out, target_id_index_set::out, make_info::in, make_info::out, io::di, io::uo) is det. get_foreign_incl_fact_table_files(ProgressStream, Globals, ModuleIndex, Succeeded, TargetIdIndexSet, !Info, !IO) :- module_index_to_name(!.Info, ModuleIndex, ModuleName), get_maybe_module_dep_info(ProgressStream, Globals, ModuleName, MaybeModuleDepInfo, !Info, !IO), ( MaybeModuleDepInfo = some_module_dep_info(ModuleDepInfo), Succeeded = succeeded, module_dep_info_get_fact_tables(ModuleDepInfo, FactTableFileNames), file_names_to_index_set(set.to_sorted_list(FactTableFileNames), FactTargetIdIndexSet, !Info), module_dep_info_get_source_file_name(ModuleDepInfo, SourceFileName), module_dep_info_get_foreign_include_files(ModuleDepInfo, ForeignIncludeFiles), globals.get_backend_foreign_languages(Globals, Languages), LangSet = set.list_to_set(Languages), set.foldl2( acc_dep_file_index_for_foreign_include_if_in_langset(LangSet, SourceFileName), ForeignIncludeFiles, FactTargetIdIndexSet, TargetIdIndexSet, !Info) ; MaybeModuleDepInfo = no_module_dep_info, Succeeded = did_not_succeed, TargetIdIndexSet = index_set_init ). :- pred acc_dep_file_index_for_foreign_include_if_in_langset( set(foreign_language)::in, file_name::in, foreign_include_file_info::in, target_id_index_set::in, target_id_index_set::out, make_info::in, make_info::out) is det. acc_dep_file_index_for_foreign_include_if_in_langset(LangSet, SourceFileName, ForeignInclude, !TargetIdIndexSet, !Info) :- ForeignInclude = foreign_include_file_info(Lang, IncludeFileName), ( if set.contains(LangSet, Lang) then make_include_file_path(SourceFileName, IncludeFileName, IncludePath), TargetId = timi_non_merc(IncludePath), target_id_to_index(TargetId, TargetIdIndex, !Info), index_set_insert(TargetIdIndex, !TargetIdIndexSet) else true ). %---------------------------------------------------------------------------% %---------------------------------------------------------------------------% :- pred find_transitive_implementation_imports(io.text_output_stream::in, maybe_keep_going::in, globals::in, module_index::in, maybe_succeeded::out, module_index_set::out, make_info::in, make_info::out, io::di, io::uo) is det. find_transitive_implementation_imports(ProgressStream, _KeepGoing, Globals, ModuleIndex, Succeeded, Modules, !Info, !IO) :- % XXX MDNEW process_modules_anywhere allows a .module_dep file % from a directory far down a search path to create a reference % to a module that exists in the *current* directory, if its name % duplicates the name of a module in the .module_dep file's directory. % This caused the failure of e.g. the warnings/bug311 test case, % with the module in the current directory being time.m (until % that module was renamed specially in order to avoid such failures). find_transitive_module_dependencies(ProgressStream, Globals, all_imports, process_modules_anywhere, ModuleIndex, Succeeded, Modules0, !Info, !IO), index_set_insert(ModuleIndex, Modules0, Modules), trace [ compile_time(flag("find_trans_impl_imports")), run_time(env("FIND_TRANS_IMPL_IMPORTS")), io(!TIO) ] ( module_index_to_name(!.Info, ModuleIndex, IndexModuleName), IndexModuleNameStr = sym_name_to_string(IndexModuleName), module_index_set_to_plain_set(!.Info, Modules, ModuleSet), ModuleList = set.to_sorted_list(ModuleSet), ModuleNlStrs = list.map( (func(M) = " " ++ sym_name_to_string(M) ++ "\n"), ModuleList), io.format(ProgressStream, "trans impl imports for %s:\n", [s(IndexModuleNameStr)], !TIO), list.foldl(io.write_string(ProgressStream), ModuleNlStrs, !TIO), io.write_string(ProgressStream, "trans impl imports list ends\n\n", !TIO) ). %---------------------------------------------------------------------------% :- pred find_local_modules(io.text_output_stream::in, list(module_index)::in, module_index_set::in, module_index_set::out, make_info::in, make_info::out, io::di, io::uo) is det. find_local_modules(_ProgressStream, [], !LocalModuleIndexSet, !Info, !IO). find_local_modules(ProgressStream, [ModuleIndex | ModuleIndexes], !LocalModuleIndexSet, !Info, !IO) :- SrcIsLocalMap0 = make_info_get_module_src_is_local_map(!.Info), ( if map.search(SrcIsLocalMap0, ModuleIndex, IsLocal0) then ( IsLocal0 = src_is_local, index_set_insert(ModuleIndex, !LocalModuleIndexSet) ; IsLocal0 = src_is_not_local ) else module_index_to_name(!.Info, ModuleIndex, ModuleName), module_name_to_source_file_name(ModuleName, FileName, !IO), io.open_input(FileName, OpenResult, !IO), ( OpenResult = ok(InputStream), io.close_input(InputStream, !IO), index_set_insert(ModuleIndex, !LocalModuleIndexSet), IsLocal = src_is_local ; OpenResult = error(_), IsLocal = src_is_not_local ), map.det_insert(ModuleIndex, IsLocal, SrcIsLocalMap0, SrcIsLocalMap), make_info_set_module_src_is_local_map(SrcIsLocalMap, !Info) ), find_local_modules(ProgressStream, ModuleIndexes, !LocalModuleIndexSet, !Info, !IO). %---------------------------------------------------------------------------% %---------------------------------------------------------------------------% % find_module_deps(Globals, ModuleIndex, Succeeded, ModuleIndexSet, % !Info, !IO). % % The reason we don't return maybe(ModuleIndexSet) is that % with `--keep-going', we want to do as much work as possible. % :- type find_module_deps(T) == pred(io.text_output_stream, maybe_keep_going, globals, module_index, maybe_succeeded, index_set(T), make_info, make_info, io, io). :- inst find_module_deps == (pred(in, in, in, in, out, out, in, out, di, uo) is det). % fold_find_modules_over_modules(KeepGoing, Globals, FindModules, % ModuleIndexes, !Succeeded, !ModuleIndexSet, !Info, !IO): % % Invoke FindModules on each element of ModuleIndexes, adding % the union of the returned module index sets to !ModuleIndexSet. % % Stop only if an invocation of FindModules returns did_not_succeed % *and* KeepGoing is do_not_keep_going. % :- pred fold_find_modules_over_modules(io.text_output_stream::in, maybe_keep_going::in, globals::in, find_module_deps(module_index)::in(find_module_deps), list(module_index)::in, maybe_succeeded::in, maybe_succeeded::out, module_index_set::in, module_index_set::out, make_info::in, make_info::out, io::di, io::uo) is det. fold_find_modules_over_modules(_, _, _, _, [], !Succeeded, !ModuleIndexSet, !Info, !IO). fold_find_modules_over_modules(ProgressStream, KeepGoing, Globals, FindModules, [MI | MIs], !Succeeded, !ModuleIndexSet, !Info, !IO) :- FindModules(ProgressStream, KeepGoing, Globals, MI, HeadSucceeded, HeadModuleIndexSet, !Info, !IO), index_set_union(HeadModuleIndexSet, !ModuleIndexSet), should_we_stop_or_continue(KeepGoing, HeadSucceeded, StopOrContinue, !Succeeded), ( StopOrContinue = soc_stop ; StopOrContinue = soc_continue, fold_find_modules_over_modules(ProgressStream, KeepGoing, Globals, FindModules, MIs, !Succeeded, !ModuleIndexSet, !Info, !IO) ). %---------------------% % fold_prereq_spec_over_modules(ProgressStream, KeepGoing, Globals, % PrereqSpec, ModuleIndexes, !Succeeded, !TargetIdIndexSet, !Info, !IO): % % Invoke find_prereqs_from_spec with PrereqSpec on each element of % ModuleIndexes, adding the union of the resulting dependency file % index sets to !TargetIdIndexSet. % % Stop only if an invocation of find_prereqs_from_spec returns % did_not_succeed *and* KeepGoing is do_not_keep_going. % :- pred fold_prereq_spec_over_modules(io.text_output_stream::in, maybe_keep_going::in, globals::in, prereq_spec::in, list(module_index)::in, maybe_succeeded::in, maybe_succeeded::out, target_id_index_set::in, target_id_index_set::out, make_info::in, make_info::out, io::di, io::uo) is det. fold_prereq_spec_over_modules(_, _, _, _, [], !Succeeded, !TargetIdIndexSet, !Info, !IO). fold_prereq_spec_over_modules(ProgressStream, KeepGoing, Globals, PrereqSpec, [MI | MIs], !Succeeded, !TargetIdIndexSet, !Info, !IO) :- find_prereqs_from_spec(ProgressStream, KeepGoing, Globals, MI, PrereqSpec, HeadSucceeded, HeadTargetIdIndexSet, !Info, !IO), index_set_union(HeadTargetIdIndexSet, !TargetIdIndexSet), should_we_stop_or_continue(KeepGoing, HeadSucceeded, StopOrContinue, !Succeeded), ( StopOrContinue = soc_stop ; StopOrContinue = soc_continue, fold_prereq_spec_over_modules(ProgressStream, KeepGoing, Globals, PrereqSpec, MIs, !Succeeded, !TargetIdIndexSet, !Info, !IO) ). %---------------------------------------------------------------------------% %---------------------------------------------------------------------------% :- func target_id_to_debug_string(string, string, target_id) = string. target_id_to_debug_string(Prefix, Suffix, TargetId) = Str :- ( TargetId = merc_target(TargetFile), TargetFile = target_file(ModuleName, TargetType), ModuleNameStr = sym_name_to_string(ModuleName), TargetTypeStr = string.string(TargetType), string.format("merc_target %s of %s", [s(TargetTypeStr), s(ModuleNameStr)], Str0) ; TargetId = non_merc_target(FileName), string.format("non_term_target %s", [s(FileName)], Str0) ), Str = Prefix ++ Str0 ++ Suffix. %---------------------------------------------------------------------------% :- end_module make.prereqs. %---------------------------------------------------------------------------%