Commit 90bf3139 authored by simonpj's avatar simonpj
Browse files

[project @ 2003-01-13 13:20:37 by simonpj]

--------------------------------
	Don't export the inlining for a foreign
	import that has a #include directive
	--------------------------------

Reason for this change: if the inlining is imported into another
module, the latter may not have the right #include directives.

Also add notes to the documentation to explain the issues.
parent 67398e1b
......@@ -120,30 +120,50 @@ dsFImport :: Id
-> ForeignImport
-> DsM ([Binding], SDoc, SDoc, [FastString])
dsFImport id (CImport cconv safety header lib spec)
= dsCImport id spec cconv safety `thenDs` \(ids, h, c) ->
returnDs (ids, h, c, if nullFastString header then [] else [header])
= dsCImport id spec cconv safety no_hdrs `thenDs` \(ids, h, c) ->
returnDs (ids, h, c, if no_hdrs then [] else [header])
where
no_hdrs = nullFastString header
-- FIXME: the `lib' field is needed for .NET ILX generation when invoking
-- routines that are external to the .NET runtime, but GHC doesn't
-- support such calls yet; if `nullFastString lib', the value was not given
dsFImport id (DNImport spec)
= dsFCall id (DNCall spec) `thenDs` \(ids, h, c) ->
= dsFCall id (DNCall spec) True {- No headers -} `thenDs` \(ids, h, c) ->
returnDs (ids, h, c, [])
dsCImport :: Id
-> CImportSpec
-> CCallConv
-> Safety
-> Bool -- True <=> no headers in the f.i decl
-> DsM ([Binding], SDoc, SDoc)
dsCImport id (CLabel cid) _ _
dsCImport id (CLabel cid) _ _ no_hdrs
= ASSERT(fromJust resTy `eqType` addrPrimTy) -- typechecker ensures this
returnDs ([(id, rhs)], empty, empty)
returnDs ([(setImpInline no_hdrs id, rhs)], empty, empty)
where
(resTy, foRhs) = resultWrapper (idType id)
rhs = foRhs (mkLit (MachLabel cid))
dsCImport id (CFunction target) cconv safety
= dsFCall id (CCall (CCallSpec target cconv safety))
dsCImport id CWrapper cconv _
dsCImport id (CFunction target) cconv safety no_hdrs
= dsFCall id (CCall (CCallSpec target cconv safety)) no_hdrs
dsCImport id CWrapper cconv _ _
= dsFExportDynamic id cconv
setImpInline :: Bool -- True <=> No #include headers
-- in the foreign import declaration
-> Id -> Id
-- If there is a #include header in the foreign import
-- we make the worker non-inlinable, because we currently
-- don't keep the #include stuff in the CCallId, and hence
-- it won't be visible in the importing module, which can be
-- fatal.
-- (The #include stuff is just collected from the foreign import
-- decls in a module.)
-- If you want to do cross-module inlining of the c-calls themselves,
-- put the #include stuff in the package spec, not the foreign
-- import decl.
setImpInline True id = id
setImpInline False id = id `setInlinePragma` NeverActive
\end{code}
......@@ -154,7 +174,7 @@ dsCImport id CWrapper cconv _
%************************************************************************
\begin{code}
dsFCall fn_id fcall
dsFCall fn_id fcall no_hdrs
= let
ty = idType fn_id
(tvs, fun_ty) = tcSplitForAllTys ty
......@@ -183,7 +203,8 @@ dsFCall fn_id fcall
worker_ty = mkForAllTys tvs (mkFunTys (map idType work_arg_ids) ccall_result_ty)
the_ccall_app = mkFCall ccall_uniq fcall val_args ccall_result_ty
work_rhs = mkLams tvs (mkLams work_arg_ids the_ccall_app)
work_id = mkSysLocal (encodeFS FSLIT("$wccall")) work_uniq worker_ty
work_id = setImpInline no_hdrs $ -- See comments with setImpInline
mkSysLocal (encodeFS FSLIT("$wccall")) work_uniq worker_ty
-- Build the wrapper
work_app = mkApps (mkVarApps (Var work_id) tvs) val_args
......
......@@ -226,7 +226,6 @@ int main(int argc, char *argv[])
<indexterm><primary>C calls, function headers</primary></indexterm>
<para>When generating C (using the <option>-fvia-C</option>
directive), one can assist the C compiler in detecting type
errors by using the <option>-&num;include</option> directive
(<xref linkend="options-C-compiler">) to provide
......@@ -256,6 +255,37 @@ HsInt lookupEFS (HsForeignObj a, HsInt i);
Thing for anyone who cares about writing solid code. You're
crazy not to do it.</para>
<para>
What if you are importing a module from another package, and
a cross-module inlining exposes a foreign call that needs a supporting
<option>-&num;include</option>? If the imported module is from the same package as
the module being compiled, you should supply all the <option>-&num;include</option>
that you supplied when compiling the imported module. If the imported module comes
from another package, you won't necessarily know what the appropriate
<option>-&num;include</option> options are; but they should be in the package
configuration, which GHC knows about. So if you are building a package, remember
to put all those <option>-&num;include</option> options into the package configuration.
See the <literal>c_includes</literal> field in <xref linkend="package-management">.
</para>
<para>
It is also possible, according the FFI specification, to put the
<option>-&num;include</option> option in the foreign import
declaration itself:
<programlisting>
foreign import "#include foo.h f" f :: Int -> IO Int
</programlisting>
When compiling this module, GHC will generate a C file that includes
the specified <option>-&num;include</option>. However, GHC
<emphasis>disables</emphasis> cross-module inlinding for such foreign
calls, because it doesn't transport the <option>-&num;include</option>
information across module boundaries. (There is no fundamental reason for this;
it was just tiresome to implement. The wrapper, which unboxes the arguments
etc, is still inlined across modules.) So if you want the foreign call itself
to be inlined across modules, use the command-line and package-configuration
<option>-&num;include</option> mechanism.
</para>
</sect2>
</sect1>
</Chapter>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment