Files
mercury/compiler/compile_target_code.m
Peter Ross dc060b2ed3 Fix a bug in my previous change to fix a bug in fjh's previous change.
Estimated hours taken: 0.5
Branches: main

Fix a bug in my previous change to fix a bug in fjh's previous change.
Revert back to using '/out:', and instead add the flag '/link' so that '/out:'
is passed to the linker instead to avoid problems compiling the library.

scripts/Mmake.rules:
compiler/compile_target_code.m:
	Add '/link' before the '/out:'.

scripts/Mmake.rules:
	Also add fjh's change for /LD to other rules building .dlls.
2002-11-15 12:09:18 +00:00

1238 lines
40 KiB
Mathematica

%-----------------------------------------------------------------------------%
% Copyright (C) 2002 University of Melbourne.
% This file may only be copied under the terms of the GNU General
% Public License - see the file COPYING in the Mercury distribution.
%-----------------------------------------------------------------------------%
% File: compile_target_code.m
% Main authors: fjh, stayl
%
% Code to compile the generated `.c', `.s', `.o', etc, files.
%
%-----------------------------------------------------------------------------%
:- module backend_libs__compile_target_code.
:- interface.
:- import_module parse_tree__prog_data, parse_tree__prog_io.
:- import_module parse_tree__modules.
:- import_module bool, list, io, std_util.
% Are we generating position independent code (for use in a
% shared library)? On some architectures, pic and non-pic
% code is incompatible, so we need to generate `.o' and `.pic_o'
% files.
:- type pic
---> pic
; non_pic
.
% compile_c_file(ErrorStream, PIC, CFile, ObjFile, Succeeded).
:- pred compile_c_file(io__output_stream, pic, string, string, bool,
io__state, io__state).
:- mode compile_c_file(in, in, in, in, out, di, uo) is det.
% compile_c_file(ErrorStream, PIC, ModuleName, Succeeded).
:- pred compile_c_file(io__output_stream, pic, module_name, bool,
io__state, io__state).
:- mode compile_c_file(in, in, in, out, di, uo) is det.
% assemble(ErrorStream, PIC, ModuleName, Succeeded).
:- pred assemble(io__output_stream, pic, module_name,
bool, io__state, io__state).
:- mode assemble(in, in, in, out, di, uo) is det.
% compile_java_file(ErrorStream, ModuleName, Succeeded).
:- pred compile_java_file(io__output_stream, module_name, bool,
io__state, io__state).
:- mode compile_java_file(in, in, out, di, uo) is det.
% il_assemble(ErrorStream, ModuleName, HasMain, Succeeded).
:- pred il_assemble(io__output_stream, module_name,
has_main, bool, io__state, io__state).
:- mode il_assemble(in, in, in, out, di, uo) is det.
% il_assemble(ErrorStream, ILFile, DLLFile, HasMain, Succeeded).
:- pred il_assemble(io__output_stream, file_name, file_name,
has_main, bool, io__state, io__state).
:- mode il_assemble(in, in, in, in, out, di, uo) is det.
% compile_managed_cplusplus_file(ErrorStream,
% MCPPFile, DLLFile, Succeeded).
:- pred compile_managed_cplusplus_file(io__output_stream,
file_name, file_name, bool, io__state, io__state).
:- mode compile_managed_cplusplus_file(in, in, in, out, di, uo) is det.
% compile_csharp_file(ErrorStream, C#File, DLLFile, Succeeded).
:- pred compile_csharp_file(io__output_stream, file_name, file_name,
bool, io__state, io__state).
:- mode compile_csharp_file(in, in, in, out, di, uo) is det.
% make_init_file(ErrorStream, MainModuleName, ModuleNames, Succeeded).
%
% Make the `.init' file for a library containing the given modules.
:- pred make_init_file(io__output_stream, module_name,
list(module_name), bool, io__state, io__state).
:- mode make_init_file(in, in, in, out, di, uo) is det.
% make_init_obj_file(ErrorStream, MainModuleName,
% AllModuleNames, MaybeInitObjFileName).
:- pred make_init_obj_file(io__output_stream, module_name, list(module_name),
maybe(file_name), io__state, io__state).
:- mode make_init_obj_file(in, in, in, out, di, uo) is det.
:- type linked_target_type
---> executable
; static_library
; shared_library
.
% link(TargetType, MainModuleName, ObjectFileNames, Succeeded).
:- pred link(io__output_stream, linked_target_type, module_name,
list(string), bool, io__state, io__state).
:- mode link(in, in, in, in, out, di, uo) is det.
% link_module_list(ModulesToLink, Succeeded).
%
% The elements of ModulesToLink are the output of
% `module_name_to_filename(ModuleName, "", no, ModuleToLink)'
% for each module in the program.
:- pred link_module_list(list(string), bool, io__state, io__state).
:- mode link_module_list(in, out, di, uo) is det.
%-----------------------------------------------------------------------------%
% Code to deal with `--split-c-files'.
% split_c_to_obj(ErrorStream, ModuleName, NumChunks, Succeeded).
% Compile the `.c' files produced for a module with `--split-c-files'.
:- pred split_c_to_obj(io__output_stream, module_name,
int, bool, io__state, io__state).
:- mode split_c_to_obj(in, in, in, out, di, uo) is det.
% Write the number of `.c' files written by this
% compilation with `--split-c-files'.
:- pred write_num_split_c_files(module_name, int, bool, io__state, io__state).
:- mode write_num_split_c_files(in, in, out, di, uo) is det.
% Find the number of `.c' files written by a previous
% compilation with `--split-c-files'.
:- pred read_num_split_c_files(module_name, maybe_error(int),
io__state, io__state).
:- mode read_num_split_c_files(in, out, di, uo) is det.
% remove_split_c_output_files(ModuleName, NumChunks).
%
% Remove the `.c' and `.o' files written by a previous
% compilation with `--split-c-files'.
:- pred remove_split_c_output_files(module_name, int, io__state, io__state).
:- mode remove_split_c_output_files(in, in, di, uo) is det.
%-----------------------------------------------------------------------------%
% substitute_user_command(Command0, ModuleName,
% AllModuleNames) = Command
%
% Replace all occurrences of `@' in Command with ModuleName,
% and replace occurrences of `%' in Command with AllModuleNames.
% This is used to implement the `--pre-link-command' and
% `--make-init-file-command' options.
:- func substitute_user_command(string, module_name,
list(module_name)) = string.
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module libs__globals, libs__options, libs__handle_options.
:- import_module hlds__passes_aux, libs__trace_params.
:- import_module parse_tree__prog_out.
:- import_module ll_backend__llds_out. % for llds_out__make_init_name and
% llds_out__make_rl_data_name
:- import_module char, dir, getopt, int, require, string.
il_assemble(ErrorStream, ModuleName,
HasMain, Succeeded) -->
module_name_to_file_name(ModuleName, ".il", no, IL_File),
( { HasMain = has_main } ->
module_name_to_file_name(ModuleName, ".exe", yes, TargetFile)
;
module_name_to_file_name(ModuleName, ".dll", yes, TargetFile)
),
il_assemble(ErrorStream, IL_File, TargetFile,
HasMain, Succeeded).
il_assemble(ErrorStream, IL_File, TargetFile,
HasMain, Succeeded) -->
globals__io_lookup_bool_option(verbose, Verbose),
globals__io_lookup_bool_option(sign_assembly, SignAssembly),
maybe_write_string(Verbose, "% Assembling `"),
maybe_write_string(Verbose, IL_File),
maybe_write_string(Verbose, "':\n"),
globals__io_lookup_string_option(il_assembler, ILASM),
globals__io_lookup_accumulating_option(ilasm_flags, ILASMFlagsList),
{ join_string_list(ILASMFlagsList, "", "", " ", ILASMFlags) },
{ SignAssembly = yes ->
SignOpt = "/keyf=mercury.sn "
;
SignOpt = ""
},
{ Verbose = yes ->
VerboseOpt = ""
;
VerboseOpt = "/quiet "
},
globals__io_lookup_bool_option(target_debug, Debug),
{ Debug = yes ->
DebugOpt = "/debug "
;
DebugOpt = ""
},
{ HasMain = has_main ->
TargetOpt = ""
;
TargetOpt = "/dll "
},
{ string__append_list([ILASM, " ", SignOpt, VerboseOpt, DebugOpt,
TargetOpt, ILASMFlags, " /out=", TargetFile,
" ", IL_File], Command) },
invoke_system_command(ErrorStream, verbose_commands,
Command, Succeeded).
compile_managed_cplusplus_file(ErrorStream,
MCPPFileName, DLLFileName, Succeeded) -->
globals__io_lookup_bool_option(verbose, Verbose),
maybe_write_string(Verbose, "% Compiling `"),
maybe_write_string(Verbose, MCPPFileName),
maybe_write_string(Verbose, "':\n"),
globals__io_lookup_string_option(mcpp_compiler, MCPP),
globals__io_lookup_accumulating_option(mcpp_flags, MCPPFlagsList),
{ join_string_list(MCPPFlagsList, "", "", " ", MCPPFlags) },
globals__io_lookup_bool_option(target_debug, Debug),
{ Debug = yes ->
DebugOpt = "/Zi "
;
DebugOpt = ""
},
% XXX Should we introduce a `--mcpp-include-directory' option?
globals__io_lookup_accumulating_option(c_include_directory,
C_Incl_Dirs),
{ InclOpts = string__append_list(list__condense(list__map(
(func(C_INCL) = ["-I", C_INCL, " "]), C_Incl_Dirs))) },
% XXX Should we use a separate dll_directories options?
globals__io_lookup_accumulating_option(link_library_directories,
DLLDirs),
{ DLLDirOpts = string__append_list(list__condense(list__map(
(func(DLLDir) = ["-AI", DLLDir, " "]), DLLDirs))) },
{ string__append_list([MCPP, " -CLR ", DebugOpt, InclOpts,
DLLDirOpts, MCPPFlags, " ", MCPPFileName,
" /LD /link -out:", DLLFileName],
Command) },
invoke_system_command(ErrorStream, verbose_commands,
Command, Succeeded).
compile_csharp_file(ErrorStream,
CSharpFileName, DLLFileName, Succeeded) -->
globals__io_lookup_bool_option(verbose, Verbose),
maybe_write_string(Verbose, "% Compiling `"),
maybe_write_string(Verbose, CSharpFileName),
maybe_write_string(Verbose, "':\n"),
globals__io_lookup_string_option(csharp_compiler, CSC),
globals__io_lookup_accumulating_option(csharp_flags, CSCFlagsList),
{ join_string_list(CSCFlagsList, "", "", " ", CSCFlags) },
globals__io_lookup_bool_option(target_debug, Debug),
{ Debug = yes ->
% XXX This needs testing before it can be enabled
% (see the comments for install_debug_library in
% library/Mmakefile).
% DebugOpt = "/debug+ /debug:full "
DebugOpt = ""
;
DebugOpt = ""
},
% XXX Should we use a separate dll_directories options?
globals__io_lookup_accumulating_option(link_library_directories,
DLLDirs),
{ DLLDirOpts = string__append_list(list__condense(list__map(
(func(DLLDir) = ["/lib:", DLLDir, " "]), DLLDirs))) },
{ string__append_list([CSC, " -CLR ", DebugOpt,
"/t:library ", DLLDirOpts, CSCFlags,
" /out:", DLLFileName, " ", CSharpFileName], Command) },
invoke_system_command(ErrorStream, verbose_commands,
Command, Succeeded).
%-----------------------------------------------------------------------------%
split_c_to_obj(ErrorStream, ModuleName, NumChunks, Succeeded) -->
split_c_to_obj(ErrorStream, ModuleName, 0, NumChunks, Succeeded).
% compile each of the C files in `<module>.dir'
:- pred split_c_to_obj(io__output_stream, module_name,
int, int, bool, io__state, io__state).
:- mode split_c_to_obj(in, in, in, in, out, di, uo) is det.
split_c_to_obj(ErrorStream, ModuleName,
Chunk, NumChunks, Succeeded) -->
( { Chunk > NumChunks } ->
{ Succeeded = yes }
;
globals__io_lookup_string_option(object_file_extension, Obj),
module_name_to_split_c_file_name(ModuleName, Chunk,
".c", C_File),
module_name_to_split_c_file_name(ModuleName, Chunk,
Obj, O_File),
compile_c_file(ErrorStream, non_pic,
C_File, O_File, Succeeded0),
( { Succeeded0 = no } ->
{ Succeeded = no }
;
{ Chunk1 is Chunk + 1 },
split_c_to_obj(ErrorStream,
ModuleName, Chunk1, NumChunks, Succeeded)
)
).
% WARNING: The code here duplicates the functionality of scripts/mgnuc.in.
% Any changes there may also require changes here, and vice versa.
:- type compiler_type ---> gcc ; lcc ; cl ; unknown.
compile_c_file(ErrorStream, PIC, ModuleName, Succeeded) -->
module_name_to_file_name(ModuleName, ".c", yes, C_File),
(
{ PIC = pic },
globals__io_lookup_string_option(pic_object_file_extension,
ObjExt)
;
{ PIC = non_pic },
globals__io_lookup_string_option(object_file_extension, ObjExt)
),
module_name_to_file_name(ModuleName, ObjExt, yes, O_File),
compile_c_file(ErrorStream, PIC, C_File, O_File, Succeeded).
compile_c_file(ErrorStream, PIC, C_File, O_File, Succeeded) -->
globals__io_lookup_bool_option(verbose, Verbose),
globals__io_lookup_string_option(c_flag_to_name_object_file,
NameObjectFile),
maybe_write_string(Verbose, "% Compiling `"),
maybe_write_string(Verbose, C_File),
maybe_write_string(Verbose, "':\n"),
globals__io_lookup_string_option(cc, CC),
globals__io_lookup_accumulating_option(cflags, C_Flags_List),
{ join_string_list(C_Flags_List, "", "", " ", CFLAGS) },
{ string__sub_string_search(CC, "gcc", _) ->
CompilerType = gcc
; string__sub_string_search(CC, "lcc", _) ->
CompilerType = lcc
; string__sub_string_search(string__to_lower(CC), "cl", _) ->
CompilerType = cl
;
CompilerType = unknown
},
(
{ PIC = pic },
globals__io_lookup_string_option(cflags_for_pic,
CFLAGS_FOR_PIC)
;
{ PIC = non_pic },
{ CFLAGS_FOR_PIC = "" }
),
globals__io_lookup_bool_option(use_subdirs, UseSubdirs),
globals__io_lookup_bool_option(split_c_files, SplitCFiles),
{ (UseSubdirs = yes ; SplitCFiles = yes) ->
% the source file (foo.c) will be compiled in a subdirectory
% (either Mercury/cs, foo.dir, or Mercury/dirs/foo.dir,
% depending on which of these two options is set)
% so we need to add `-I.' so it can
% include header files in the source directory.
SubDirInclOpt = "-I. "
;
SubDirInclOpt = ""
},
globals__io_lookup_accumulating_option(c_include_directory,
C_Incl_Dirs),
{ InclOpt = string__append_list(list__condense(list__map(
(func(C_INCL) = ["-I", C_INCL, " "]), C_Incl_Dirs))) },
globals__io_lookup_bool_option(split_c_files, Split_C_Files),
{ Split_C_Files = yes ->
SplitOpt = "-DMR_SPLIT_C_FILES "
;
SplitOpt = ""
},
globals__io_lookup_bool_option(highlevel_code, HighLevelCode),
( { HighLevelCode = yes } ->
{ HighLevelCodeOpt = "-DMR_HIGHLEVEL_CODE " }
;
{ HighLevelCodeOpt = "" }
),
globals__io_lookup_bool_option(gcc_nested_functions,
GCC_NestedFunctions),
( { GCC_NestedFunctions = yes } ->
{ NestedFunctionsOpt = "-DMR_USE_GCC_NESTED_FUNCTIONS " }
;
{ NestedFunctionsOpt = "" }
),
globals__io_lookup_bool_option(highlevel_data, HighLevelData),
( { HighLevelData = yes } ->
{ HighLevelDataOpt = "-DMR_HIGHLEVEL_DATA " }
;
{ HighLevelDataOpt = "" }
),
globals__io_lookup_bool_option(gcc_global_registers, GCC_Regs),
( { GCC_Regs = yes } ->
globals__io_lookup_string_option(cflags_for_regs,
CFLAGS_FOR_REGS),
{ RegOpt = "-DMR_USE_GCC_GLOBAL_REGISTERS " }
;
{ CFLAGS_FOR_REGS = "" },
{ RegOpt = "" }
),
globals__io_lookup_bool_option(gcc_non_local_gotos, GCC_Gotos),
( { GCC_Gotos = yes } ->
{ GotoOpt = "-DMR_USE_GCC_NONLOCAL_GOTOS " },
globals__io_lookup_string_option(cflags_for_gotos,
CFLAGS_FOR_GOTOS)
;
{ GotoOpt = "" },
{ CFLAGS_FOR_GOTOS = "" }
),
globals__io_lookup_bool_option(asm_labels, ASM_Labels),
{ ASM_Labels = yes ->
AsmOpt = "-DMR_USE_ASM_LABELS "
;
AsmOpt = ""
},
globals__io_lookup_bool_option(parallel, Parallel),
( { Parallel = yes } ->
globals__io_lookup_string_option(cflags_for_threads,
CFLAGS_FOR_THREADS)
;
{ CFLAGS_FOR_THREADS = "" }
),
globals__io_get_gc_method(GC_Method),
{
GC_Method = boehm,
GC_Opt = "-DMR_CONSERVATIVE_GC -DMR_BOEHM_GC "
;
GC_Method = mps,
GC_Opt = "-DMR_CONSERVATIVE_GC -DMR_MPS_GC "
;
GC_Method = accurate,
GC_Opt = "-DMR_NATIVE_GC "
;
GC_Method = none,
GC_Opt = ""
},
globals__io_lookup_bool_option(profile_calls, ProfileCalls),
{ ProfileCalls = yes ->
ProfileCallsOpt = "-DMR_MPROF_PROFILE_CALLS "
;
ProfileCallsOpt = ""
},
globals__io_lookup_bool_option(profile_time, ProfileTime),
{ ProfileTime = yes ->
ProfileTimeOpt = "-DMR_MPROF_PROFILE_TIME "
;
ProfileTimeOpt = ""
},
globals__io_lookup_bool_option(profile_memory, ProfileMemory),
{ ProfileMemory = yes ->
ProfileMemoryOpt = "-DMR_MPROF_PROFILE_MEMORY "
;
ProfileMemoryOpt = ""
},
globals__io_lookup_bool_option(profile_deep, ProfileDeep),
{ ProfileDeep = yes ->
ProfileDeepOpt = "-DMR_DEEP_PROFILING "
;
ProfileDeepOpt = ""
},
globals__io_lookup_bool_option(pic_reg, PIC_Reg),
{ PIC_Reg = yes ->
PIC_Reg_Opt = "-DMR_PIC_REG "
;
PIC_Reg_Opt = ""
},
globals__io_get_tags_method(Tags_Method),
{ Tags_Method = high ->
TagsOpt = "-DMR_HIGHTAGS "
;
TagsOpt = ""
},
globals__io_lookup_int_option(num_tag_bits, NumTagBits),
{ string__int_to_string(NumTagBits, NumTagBitsString) },
{ string__append_list(
["-DMR_TAGBITS=", NumTagBitsString, " "], NumTagBitsOpt) },
globals__io_lookup_bool_option(decl_debug, DeclDebug),
{ DeclDebug = yes ->
DeclDebugOpt = "-DMR_DECL_DEBUG "
;
DeclDebugOpt = ""
},
globals__io_lookup_bool_option(require_tracing, RequireTracing),
{ RequireTracing = yes ->
RequireTracingOpt = "-DMR_REQUIRE_TRACING "
;
RequireTracingOpt = ""
},
globals__io_lookup_bool_option(stack_trace, StackTrace),
{ StackTrace = yes ->
StackTraceOpt = "-DMR_STACK_TRACE "
;
StackTraceOpt = ""
},
globals__io_lookup_bool_option(target_debug, Target_Debug),
{ Target_Debug = yes ->
( CompilerType = gcc,
Target_DebugOpt = "-g "
; CompilerType = lcc,
Target_DebugOpt = "-g "
; CompilerType = cl,
Target_DebugOpt = "/Zi "
; CompilerType = unknown,
Target_DebugOpt = "-g "
)
;
Target_DebugOpt = ""
},
globals__io_lookup_bool_option(low_level_debug, LL_Debug),
{ LL_Debug = yes ->
LL_DebugOpt = "-DMR_LOW_LEVEL_DEBUG "
;
LL_DebugOpt = ""
},
globals__io_lookup_bool_option(use_trail, UseTrail),
{ UseTrail = yes ->
UseTrailOpt = "-DMR_USE_TRAIL "
;
UseTrailOpt = ""
},
globals__io_lookup_bool_option(reserve_tag, ReserveTag),
{ ReserveTag = yes ->
ReserveTagOpt = "-DMR_RESERVE_TAG "
;
ReserveTagOpt = ""
},
globals__io_lookup_bool_option(use_minimal_model, MinimalModel),
{ MinimalModel = yes ->
MinimalModelOpt = "-DMR_USE_MINIMAL_MODEL "
;
MinimalModelOpt = ""
},
globals__io_lookup_bool_option(type_layout, TypeLayoutOption),
{ TypeLayoutOption = no ->
TypeLayoutOpt = "-DMR_NO_TYPE_LAYOUT "
;
TypeLayoutOpt = ""
},
globals__io_lookup_bool_option(c_optimize, C_optimize),
{ C_optimize = yes ->
( CompilerType = gcc ->
OptimizeOpt = "-O2 -fomit-frame-pointer "
; CompilerType = lcc ->
OptimizeOpt = ""
;
OptimizeOpt = "-O "
)
;
OptimizeOpt = ""
},
globals__io_lookup_bool_option(inline_alloc, InlineAlloc),
{ InlineAlloc = yes ->
InlineAllocOpt = "-DMR_INLINE_ALLOC -DSILENT "
;
InlineAllocOpt = ""
},
{ CompilerType = gcc ->
% We don't enable `-Wpointer-arith', because it causes
% too many complaints in system header files.
% This is fixed in gcc 3.0, though, so at some
% point we should re-enable this.
%
% If --inline-alloc is enabled, don't enable missing-prototype
% warnings, since gc_inline.h is missing lots of prototypes.
%
% For a full list of the other gcc warnings that we don't
% enable, and why, see scripts/mgnuc.in.
( InlineAlloc = yes ->
WarningOpt = "-Wall -Wwrite-strings -Wshadow -Wmissing-prototypes -Wno-unused -Wno-uninitialized "
;
WarningOpt = "-Wall -Wwrite-strings -Wshadow -Wmissing-prototypes -Wno-unused -Wno-uninitialized -Wstrict-prototypes "
)
; CompilerType = lcc ->
WarningOpt = "-w "
;
WarningOpt = ""
},
% Be careful with the order here! Some options override others,
% e.g. CFLAGS_FOR_REGS must come after OptimizeOpt so that
% it can override -fomit-frame-pointer with -fno-omit-frame-pointer.
% Also be careful that each option is separated by spaces.
{ string__append_list([CC, " ", SubDirInclOpt, InclOpt,
SplitOpt, OptimizeOpt,
HighLevelCodeOpt, NestedFunctionsOpt, HighLevelDataOpt,
RegOpt, GotoOpt, AsmOpt,
CFLAGS_FOR_REGS, " ", CFLAGS_FOR_GOTOS, " ",
CFLAGS_FOR_THREADS, " ", CFLAGS_FOR_PIC, " ",
GC_Opt, ProfileCallsOpt, ProfileTimeOpt, ProfileMemoryOpt,
ProfileDeepOpt, PIC_Reg_Opt, TagsOpt, NumTagBitsOpt,
Target_DebugOpt, LL_DebugOpt,
DeclDebugOpt, RequireTracingOpt, StackTraceOpt,
UseTrailOpt, ReserveTagOpt, MinimalModelOpt, TypeLayoutOpt,
InlineAllocOpt, WarningOpt, CFLAGS,
" -c ", C_File, " ", NameObjectFile, O_File], Command) },
invoke_system_command(ErrorStream, verbose_commands,
Command, Succeeded).
%-----------------------------------------------------------------------------%
compile_java_file(ErrorStream, ModuleName, Succeeded) -->
module_name_to_file_name(ModuleName, ".java", no, JavaFile),
globals__io_lookup_bool_option(verbose, Verbose),
maybe_write_string(Verbose, "% Compiling `"),
maybe_write_string(Verbose, JavaFile),
maybe_write_string(Verbose, "':\n"),
globals__io_lookup_string_option(java_compiler, JavaCompiler),
globals__io_lookup_accumulating_option(java_flags, JavaFlagsList),
{ join_string_list(JavaFlagsList, "", "", " ", JAVAFLAGS) },
globals__io_lookup_accumulating_option(java_classpath,
Java_Incl_Dirs),
( { Java_Incl_Dirs = [] } ->
{ InclOpt = "" }
;
% XXX PathSeparator should be ";" on Windows
{ PathSeparator = ":" },
{ join_string_list(Java_Incl_Dirs, "", "",
PathSeparator, ClassPath) },
{ InclOpt = string__append_list([
"-classpath ", quote_arg(ClassPath), " "]) }
),
globals__io_lookup_bool_option(target_debug, Target_Debug),
{ Target_Debug = yes ->
Target_DebugOpt = "-g "
;
Target_DebugOpt = ""
},
% Be careful with the order here! Some options may override others.
% Also be careful that each option is separated by spaces.
{ string__append_list([JavaCompiler, " ", InclOpt,
Target_DebugOpt, JAVAFLAGS, JavaFile], Command) },
invoke_system_command(ErrorStream, verbose_commands,
Command, Succeeded).
%-----------------------------------------------------------------------------%
assemble(ErrorStream, PIC, ModuleName, Succeeded) -->
globals__io_lookup_bool_option(pic, Pic),
{ ( Pic = yes ; PIC = pic ) ->
AsmExt = ".pic_s",
GCCFLAGS_FOR_PIC = ""
;
AsmExt = ".s",
GCCFLAGS_FOR_PIC = "-fpic"
},
module_name_to_file_name(ModuleName, AsmExt, no, AsmFile),
globals__io_lookup_string_option(object_file_extension, Obj),
module_name_to_file_name(ModuleName, Obj, yes, ObjFile),
globals__io_lookup_bool_option(verbose, Verbose),
maybe_write_string(Verbose, "% Assembling `"),
maybe_write_string(Verbose, AsmFile),
maybe_write_string(Verbose, "':\n"),
% XXX should we use new asm_* options rather than
% reusing cc, cflags, c_flag_to_name_object_file?
globals__io_lookup_string_option(cc, CC),
globals__io_lookup_string_option(c_flag_to_name_object_file,
NameObjectFile),
globals__io_lookup_accumulating_option(cflags, C_Flags_List),
{ join_string_list(C_Flags_List, "", "", " ", CFLAGS) },
% Be careful with the order here.
% Also be careful that each option is separated by spaces.
{ string__append_list([CC, " ", CFLAGS, " ", GCCFLAGS_FOR_PIC,
" -c ", AsmFile, " ", NameObjectFile, ObjFile], Command) },
invoke_system_command(ErrorStream, verbose_commands,
Command, Succeeded).
%-----------------------------------------------------------------------------%
make_init_file(ErrorStream, MainModuleName, AllModules, Succeeded) -->
module_name_to_file_name(MainModuleName, ".init.tmp",
yes, TmpInitFileName),
io__open_output(TmpInitFileName, InitFileRes),
(
{ InitFileRes = ok(InitFileStream) },
globals__io_lookup_bool_option(aditi, Aditi),
list__foldl(
(pred(ModuleName::in, di, uo) is det -->
{ llds_out__make_init_name(ModuleName,
InitFuncName0) },
{ InitFuncName = InitFuncName0 ++ "init" },
io__write_string(InitFileStream, "INIT "),
io__write_string(InitFileStream, InitFuncName),
io__nl(InitFileStream),
( { Aditi = yes } ->
{ llds_out__make_rl_data_name(ModuleName,
RLName) },
io__write_string(InitFileStream,
"ADITI_DATA "),
io__write_string(InitFileStream, RLName),
io__nl(InitFileStream)
;
[]
)
), AllModules),
globals__io_lookup_maybe_string_option(extra_init_command,
MaybeInitFileCommand),
(
{ MaybeInitFileCommand = yes(InitFileCommand0) },
{ InitFileCommand = substitute_user_command(
InitFileCommand0, MainModuleName,
AllModules) },
invoke_shell_command(InitFileStream, verbose_commands,
InitFileCommand, Succeeded0)
;
{ MaybeInitFileCommand = no },
{ Succeeded0 = yes }
),
io__close_output(InitFileStream),
module_name_to_file_name(MainModuleName, ".init",
yes, InitFileName),
update_interface(InitFileName, Succeeded1),
{ Succeeded = Succeeded0 `and` Succeeded1 }
;
{ InitFileRes = error(Error) },
io__progname_base("mercury_compile", ProgName),
io__write_string(ErrorStream, ProgName),
io__write_string(ErrorStream, ": can't open `"),
io__write_string(ErrorStream, TmpInitFileName),
io__write_string(ErrorStream, "' for output:\n"),
io__nl(ErrorStream),
io__write_string(ErrorStream, io__error_message(Error)),
io__nl(ErrorStream),
{ Succeeded = no }
).
%-----------------------------------------------------------------------------%
link_module_list(Modules, Succeeded) -->
globals__io_lookup_string_option(output_file_name, OutputFileName0),
( { OutputFileName0 = "" } ->
( { Modules = [Module | _] } ->
{ OutputFileName = Module }
;
{ error("link_module_list: no modules") }
)
;
{ OutputFileName = OutputFileName0 }
),
{ file_name_to_module_name(OutputFileName, MainModuleName) },
globals__io_lookup_string_option(object_file_extension, Obj),
globals__io_get_target(Target),
globals__io_lookup_bool_option(split_c_files, SplitFiles),
io__output_stream(OutputStream),
( { Target = asm } ->
% for --target asm, we generate everything into a single object file
( { Modules = [FirstModule | _] } ->
join_module_list([FirstModule], Obj, [], ObjectsList)
;
{ error("link_module_list: no modules") }
),
{ MakeLibCmdOK = yes }
; { SplitFiles = yes } ->
globals__io_lookup_string_option(library_extension, LibExt),
module_name_to_file_name(MainModuleName, LibExt,
yes, SplitLibFileName),
{ string__append(".dir/*", Obj, DirObj) },
join_module_list(Modules, DirObj, [], ObjectList),
create_archive(OutputStream, SplitLibFileName,
ObjectList, MakeLibCmdOK),
{ ObjectsList = [SplitLibFileName] }
;
{ MakeLibCmdOK = yes },
join_module_list(Modules, Obj, [], ObjectsList)
),
( { MakeLibCmdOK = no } ->
{ Succeeded = no }
;
globals__io_lookup_bool_option(compile_to_shared_lib,
CompileToSharedLib),
{ TargetType =
(CompileToSharedLib = yes -> shared_library ; executable) },
( { TargetType = executable } ->
{ list__map(
(pred(ModuleStr::in, ModuleName::out) is det :-
dir__basename(ModuleStr, ModuleStrBase),
file_name_to_module_name(ModuleStrBase, ModuleName)
),
Modules, ModuleNames) },
{ MustCompile = yes },
make_init_obj_file(OutputStream, MustCompile, MainModuleName,
ModuleNames, InitObjResult)
;
{ InitObjResult = yes("") }
),
(
{ InitObjResult = yes(InitObjFileName) },
globals__io_lookup_accumulating_option(link_objects,
ExtraLinkObjectsList),
{ AllObjects0 = ObjectsList ++ ExtraLinkObjectsList },
{ AllObjects =
( InitObjFileName = "" ->
AllObjects0
;
[InitObjFileName | AllObjects0]
) },
link(OutputStream, TargetType, MainModuleName,
AllObjects, Succeeded)
;
{ InitObjResult = no },
{ Succeeded = no }
)
).
make_init_obj_file(ErrorStream,
ModuleName, ModuleNames, Result) -->
globals__io_lookup_bool_option(rebuild, MustCompile),
make_init_obj_file(ErrorStream,
MustCompile, ModuleName, ModuleNames, Result).
:- pred make_init_obj_file(io__output_stream, bool,
module_name, list(module_name), maybe(file_name),
io__state, io__state).
:- mode make_init_obj_file(in,
in, in, in, out, di, uo) is det.
make_init_obj_file(ErrorStream, MustCompile, ModuleName,
ModuleNames, Result) -->
globals__io_lookup_bool_option(verbose, Verbose),
globals__io_lookup_bool_option(statistics, Stats),
maybe_write_string(Verbose, "% Creating initialization file...\n"),
globals__io_get_trace_level(TraceLevel),
{ given_trace_level_is_none(TraceLevel) = no ->
TraceOpt = "--trace "
;
TraceOpt = ""
},
globals__io_get_globals(Globals),
{ compute_grade(Globals, Grade) },
standard_library_directory_option(StdLibOpt),
globals__io_lookup_string_option(object_file_extension, Obj),
{ string__append("_init", Obj, InitObj) },
module_name_to_file_name(ModuleName, "_init.c", yes, InitCFileName),
module_name_to_file_name(ModuleName, InitObj, yes, InitObjFileName),
list__map_foldl(
(pred(ThisModuleName::in, CFileName::out, di, uo) is det -->
module_name_to_file_name(ThisModuleName, ".c", no,
CFileName)
), ModuleNames, CFileNameList),
{ join_string_list(CFileNameList, "", "", " ", CFileNames) },
globals__io_lookup_accumulating_option(link_flags, LinkFlagsList),
{ join_string_list(LinkFlagsList, "", "", " ", LinkFlags) },
globals__io_lookup_accumulating_option(init_file_directories,
InitFileDirsList),
{ join_quoted_string_list(InitFileDirsList,
"-I ", "", " ", InitFileDirs) },
globals__io_lookup_accumulating_option(init_files, InitFileNamesList),
{ join_quoted_string_list(InitFileNamesList,
"", "", " ", InitFileNames) },
globals__io_lookup_accumulating_option(trace_init_files,
TraceInitFileNamesList),
{ join_quoted_string_list(TraceInitFileNamesList, "--trace-init-file ",
"", " ", TraceInitFileNames) },
{ TmpInitCFileName = InitCFileName ++ ".tmp" },
{ MkInitCmd = string__append_list(
["c2init --grade ", Grade, " ", TraceOpt, StdLibOpt, LinkFlags,
" --init-c-file ", TmpInitCFileName, " ", InitFileDirs, " ",
TraceInitFileNames, " ", InitFileNames, " ", CFileNames]) },
invoke_shell_command(ErrorStream, verbose, MkInitCmd, MkInitOK0),
maybe_report_stats(Stats),
( { MkInitOK0 = yes } ->
update_interface(InitCFileName, MkInitOK1),
(
{ MkInitOK1 = yes },
(
{ MustCompile = yes },
{ Compile = yes }
;
{ MustCompile = no },
io__file_modification_time(InitCFileName,
InitCModTimeResult),
io__file_modification_time(InitObjFileName,
InitObjModTimeResult),
{
InitObjModTimeResult = ok(InitObjModTime),
InitCModTimeResult = ok(InitCModTime),
compare(TimeCompare, InitObjModTime, InitCModTime),
( TimeCompare = (=)
; TimeCompare = (>)
)
->
Compile = no
;
Compile = yes
}
),
(
{ Compile = yes },
maybe_write_string(Verbose,
"% Compiling initialization file...\n"),
compile_c_file(ErrorStream, non_pic, InitCFileName,
InitObjFileName, CompileOK),
maybe_report_stats(Stats),
( { CompileOK = no } ->
{ Result = no }
;
{ Result = yes(InitObjFileName) }
)
;
{ Compile = no },
{ Result = yes(InitObjFileName) }
)
;
{ MkInitOK1 = no },
{ Result = no }
)
;
{ Result = no }
).
link(ErrorStream, LinkTargetType, ModuleName, ObjectsList, Succeeded) -->
globals__io_lookup_bool_option(verbose, Verbose),
globals__io_lookup_bool_option(statistics, Stats),
globals__io_get_trace_level(TraceLevel),
{ given_trace_level_is_none(TraceLevel) = no ->
TraceOpt = "--trace "
;
TraceOpt = ""
},
globals__io_get_globals(Globals),
{ compute_grade(Globals, Grade) },
maybe_write_string(Verbose, "% Linking...\n"),
( { LinkTargetType = static_library } ->
globals__io_lookup_string_option(library_extension, LibExt),
module_name_to_lib_file_name("lib", ModuleName, LibExt,
yes, LibName),
create_archive(ErrorStream, LibName, ObjectsList, ArCmdOK),
maybe_report_stats(Stats),
( { ArCmdOK = no } ->
{ Succeeded = no }
;
{ Succeeded = yes }
)
;
( { LinkTargetType = shared_library } ->
{ SharedLibOpt = "--make-shared-lib " },
{ LDFlagsOpt = ld_libflags },
globals__io_lookup_string_option(
shared_library_extension, SharedLibExt),
module_name_to_lib_file_name("lib", ModuleName,
SharedLibExt, yes, OutputFileName)
;
{ SharedLibOpt = "" },
{ LDFlagsOpt = ld_flags },
globals__io_lookup_string_option(
executable_file_extension, ExeExt),
module_name_to_file_name(ModuleName, ExeExt,
yes, OutputFileName)
),
globals__io_lookup_bool_option(target_debug, Target_Debug),
{ Target_Debug = yes ->
Target_Debug_Opt = "--no-strip "
;
Target_Debug_Opt = ""
},
standard_library_directory_option(StdLibOpt),
{ join_string_list(ObjectsList, "", "", " ", Objects) },
globals__io_lookup_accumulating_option(link_flags,
LinkFlagsList),
{ join_string_list(LinkFlagsList, "", "", " ", LinkFlags) },
globals__io_lookup_accumulating_option(LDFlagsOpt,
LDFlagsList),
{ join_string_list(LDFlagsList, "", "", " ", LDFlags) },
globals__io_lookup_accumulating_option(
link_library_directories,
LinkLibraryDirectoriesList),
{ join_quoted_string_list(LinkLibraryDirectoriesList, "-L", "",
" ", LinkLibraryDirectories) },
globals__io_lookup_accumulating_option(link_libraries,
LinkLibrariesList),
{ join_quoted_string_list(LinkLibrariesList, "-l", "", " ",
LinkLibraries) },
% Note that LDFlags may contain `-l' options
% so it should come after Objects.
{ string__append_list(
["ml --grade ", Grade, " ", SharedLibOpt,
Target_Debug_Opt, TraceOpt, StdLibOpt,
LinkFlags, " ", LinkLibraryDirectories,
" -- -o ", OutputFileName, " ", Objects, " ",
LDFlags, " ", LinkLibraries],
LinkCmd) },
invoke_shell_command(ErrorStream, verbose_commands,
LinkCmd, LinkSucceeded),
maybe_report_stats(Stats),
globals__io_lookup_bool_option(use_grade_subdirs,
UseGradeSubdirs),
(
{ LinkSucceeded = yes },
{ UseGradeSubdirs = yes }
->
% Link/copy the executable into the user's directory.
globals__io_set_option(use_subdirs, bool(no)),
globals__io_set_option(use_grade_subdirs, bool(no)),
module_name_to_file_name(ModuleName, "",
no, UserDirExeName),
globals__io_set_option(use_subdirs, bool(yes)),
globals__io_set_option(use_grade_subdirs, bool(yes)),
io__set_output_stream(ErrorStream, OutputStream),
make_symlink_or_copy_file(OutputFileName,
UserDirExeName, Succeeded),
io__set_output_stream(OutputStream, _)
;
{ Succeeded = LinkSucceeded }
)
).
:- pred create_archive(io__output_stream, file_name, list(file_name),
bool, io__state, io__state).
:- mode create_archive(in, in, in, out, di, uo) is det.
create_archive(ErrorStream, LibFileName, ObjectList, MakeLibCmdOK) -->
globals__io_lookup_string_option(create_archive_command, ArCmd),
globals__io_lookup_accumulating_option(
create_archive_command_flags, ArFlagsList),
{ join_string_list(ArFlagsList, "", "", " ", ArFlags) },
globals__io_lookup_string_option(
create_archive_command_output_flag, ArOutputFlag),
globals__io_lookup_string_option(ranlib_command, RanLib),
{ join_string_list(ObjectList, "", "", " ", Objects) },
{ MakeLibCmd = string__append_list([
ArCmd, " ", ArFlags, " ", ArOutputFlag, " ",
LibFileName, " ", Objects,
" && ", RanLib, " ", LibFileName]) },
invoke_system_command(ErrorStream, verbose_commands,
MakeLibCmd, MakeLibCmdOK).
%-----------------------------------------------------------------------------%
:- pred standard_library_directory_option(string, io__state, io__state).
:- mode standard_library_directory_option(out, di, uo) is det.
standard_library_directory_option(Opt) -->
globals__io_lookup_maybe_string_option(
mercury_standard_library_directory, MaybeStdLibDir),
{
MaybeStdLibDir = yes(StdLibDir),
Opt = "--mercury-standard-library-directory "
++ StdLibDir ++ " "
;
MaybeStdLibDir = no,
Opt = "--no-mercury-standard-library-directory "
}.
%-----------------------------------------------------------------------------%
% join_string_list(Strings, Prefix, Suffix, Serarator, Result)
%
% Appends the strings in the list `Strings' together into the
% string Result. Each string is prefixed by Prefix, suffixed by
% Suffix and separated by Separator.
:- pred join_string_list(list(string), string, string, string, string).
:- mode join_string_list(in, in, in, in, out) is det.
join_string_list([], _Prefix, _Suffix, _Separator, "").
join_string_list([String | Strings], Prefix, Suffix, Separator, Result) :-
( Strings = [] ->
string__append_list([Prefix, String, Suffix], Result)
;
join_string_list(Strings, Prefix, Suffix, Separator, Result0),
string__append_list([Prefix, String, Suffix, Separator,
Result0], Result)
).
% As above, but quote the strings first.
% Note that the strings in values of the *flags options are
% already quoted.
:- pred join_quoted_string_list(list(string), string, string, string, string).
:- mode join_quoted_string_list(in, in, in, in, out) is det.
join_quoted_string_list(Strings, Prefix, Suffix, Separator, Result) :-
join_string_list(map(quote_arg, Strings),
Prefix, Suffix, Separator, Result).
% join_module_list(ModuleNames, Extension, Terminator, Result)
%
% The list of strings `Result' is computed from the list of strings
% `ModuleNames', by removing any directory paths, and
% converting the strings to file names and then back,
% adding the specified Extension. (This conversion ensures
% that we follow the usual file naming conventions.)
% Each file name is separated by a space from the next one,
% and the result is followed by the list of strings `Terminator'.
:- pred join_module_list(list(string), string, list(string), list(string),
io__state, io__state).
:- mode join_module_list(in, in, in, out, di, uo) is det.
join_module_list([], _Extension, Terminator, Terminator) --> [].
join_module_list([Module | Modules], Extension, Terminator,
[FileName, " " | Rest]) -->
{ dir__basename(Module, BaseName) },
{ file_name_to_module_name(BaseName, ModuleName) },
module_name_to_file_name(ModuleName, Extension, no, FileName),
join_module_list(Modules, Extension, Terminator, Rest).
%-----------------------------------------------------------------------------%
write_num_split_c_files(ModuleName, NumChunks, Succeeded) -->
module_name_to_file_name(ModuleName, ".num_split", yes,
NumChunksFileName),
io__open_output(NumChunksFileName, Res),
( { Res = ok(OutputStream) } ->
io__write_int(OutputStream, NumChunks),
io__nl(OutputStream),
io__close_output(OutputStream),
{ Succeeded = yes }
;
{ Succeeded = no },
io__progname_base("mercury_compile", ProgName),
io__write_string(ProgName),
io__write_string(": can't open `"),
io__write_string(NumChunksFileName),
io__write_string("' for output\n")
).
read_num_split_c_files(ModuleName, MaybeNumChunks) -->
module_name_to_file_name(ModuleName, ".num_split", no,
NumChunksFileName),
io__open_input(NumChunksFileName, Res),
(
{ Res = ok(FileStream) },
io__read_word(FileStream, MaybeNumChunksString),
io__close_input(FileStream),
(
{ MaybeNumChunksString = ok(NumChunksString) },
(
{ string__to_int(
string__from_char_list(NumChunksString),
NumChunks) }
->
{ MaybeNumChunks = ok(NumChunks) }
;
{ MaybeNumChunks = error(
"Software error: error in `"
++ NumChunksFileName
++ "': expected single int.\n") }
)
;
{ MaybeNumChunksString = eof },
{ MaybeNumChunks = error(
"Software error: error in `"
++ NumChunksFileName
++ "': expected single int.\n") }
;
{ MaybeNumChunksString = error(_) },
{ MaybeNumChunks = error(
"Software error: error in `"
++ NumChunksFileName
++ "': expected single int.\n") }
)
;
{ Res = error(Error) },
{ MaybeNumChunks = error(io__error_message(Error)) }
).
remove_split_c_output_files(ModuleName, NumChunks) -->
remove_split_c_output_files(ModuleName, 0, NumChunks).
:- pred remove_split_c_output_files(module_name, int, int,
io__state, io__state).
:- mode remove_split_c_output_files(in,in, in, di, uo) is det.
remove_split_c_output_files(ModuleName, ThisChunk, NumChunks) -->
( { ThisChunk =< NumChunks } ->
globals__io_lookup_string_option(object_file_extension, Obj),
module_name_to_split_c_file_name(ModuleName, ThisChunk,
".c", CFileName),
module_name_to_split_c_file_name(ModuleName, ThisChunk,
Obj, ObjFileName),
io__remove_file(CFileName, _),
io__remove_file(ObjFileName, _),
remove_split_c_output_files(ModuleName, ThisChunk, NumChunks)
;
[]
).
%-----------------------------------------------------------------------------%
substitute_user_command(Command0, MainModule, AllModules) = Command :-
( string__contains_char(Command0, Char), (Char = ('@') ; Char = '%') ->
prog_out__sym_name_to_string(MainModule, ".", MainModuleStr),
AllModulesStrings = list__map(
(func(Module) = ModuleStr :-
prog_out__sym_name_to_string(Module, ".", ModuleStr)
), AllModules),
join_string_list(AllModulesStrings,
"", "", " ", AllModulesStr),
Command = string__from_rev_char_list(substitute_user_command_2(
string__to_char_list(Command0),
reverse(string__to_char_list(MainModuleStr)),
reverse(string__to_char_list(AllModulesStr)),
[]))
;
Command = Command0
).
:- func substitute_user_command_2(list(char), list(char),
list(char), list(char)) = list(char).
substitute_user_command_2([], _, _, RevChars) = RevChars.
substitute_user_command_2([Char | Chars], RevMainModule,
RevAllModules, RevChars0) =
(
( Char = ('@'), Subst = RevMainModule
; Char = '%', Subst = RevAllModules
)
->
( Chars = [Char | Chars2] ->
substitute_user_command_2(Chars2, RevMainModule,
RevAllModules, [Char | RevChars0])
;
substitute_user_command_2(Chars, RevMainModule,
RevAllModules, Subst ++ RevChars0)
)
;
substitute_user_command_2(Chars, RevMainModule,
RevAllModules, [Char | RevChars0])
).
%-----------------------------------------------------------------------------%