ByteCodeLink.lookupCE error during profiling build
Summary
Creating a PersistFieldSql
instance of a newtype wrapper causes a compilation error if compilation is done in a profiling mode. Writing the instance by hand works fine. The shown error is this one:
ghc: ^^ Could not load 'subprojectzm0zi0zi0zmCyhNFAzzUqYZZERicaukkM8G_Lib_zdfPersistFieldSqlTimestamp1_closure', dependency unresolved. See top entry above.
ByteCodeLink.lookupCE
During interactive linking, GHCi couldn't find the following symbol:
subprojectzm0zi0zi0zmCyhNFAzzUqYZZERicaukkM8G_Lib_zdfPersistFieldSqlTimestamp1_closure
This may be due to you not asking GHCi to load extra object files,
archives or DLLs needed by your current session. Restart GHCi, specifying
the missing library using the -L/path/to/object/dir and -lmissinglibname
flags, or simply by naming the relevant files on the GHCi command line.
Alternatively, this link failure might indicate a bug in GHCi.
If you suspect the latter, please send a bug report to:
glasgow-haskell-bugs@haskell.org
The libraries involved are:
persistent
persistent-template
I provide two minimal reproducible examples below. Essentially, there is a newtype over a Word64
whose instance PersistFieldSql
is derived using newtype deriving.
newtype Timestamp = Timestamp { tsMillis :: Word64 }
deriving newtype (PersistField, PersistFieldSql)
Writing the instance by hand results in a successful compilation:
newtype Timestamp = Timestamp { tsMillis :: Word64 }
deriving newtype (PersistField)
instance PersistFieldSql Timestamp where
sqlType _ = SqlInt64
The definition in Database.Persist.SQL
of the instance for Word64
is exactly that one as seen here:
instance PersistFieldSql Word64 where
sqlType _ = SqlInt64
In the erroneous build, checking the generated symbols on the profiling version of the library shows that the missing symbol is actually there (the third one):
> nm ./dist/x86_64-linux-tinfo6/Cabal-3.0.1.0/build/Lib.p_o | grep SqlTimestamp
0000000000000180 D subprojectzm0zi0zi0zmCyhNFAzzUqYZZERicaukkM8G_Lib_zdfPersistFieldSqlTimestamp1_CAF_cc
0000000000000280 D subprojectzm0zi0zi0zmCyhNFAzzUqYZZERicaukkM8G_Lib_zdfPersistFieldSqlTimestamp1_CAF_cc_ccs
00000000000002e0 D subprojectzm0zi0zi0zmCyhNFAzzUqYZZERicaukkM8G_Lib_zdfPersistFieldSqlTimestamp1_closure
0000000000000020 T subprojectzm0zi0zi0zmCyhNFAzzUqYZZERicaukkM8G_Lib_zdfPersistFieldSqlTimestamp1_info
00000000000003a0 D subprojectzm0zi0zi0zmCyhNFAzzUqYZZERicaukkM8G_Lib_zdfPersistFieldSqlTimestamp_closure
But in the successful build, the 1
at the end of the symbol's name is not present anymore:
> nm .stack-work/dist/x86_64-linux-tinfo6/Cabal-3.0.1.0/build/Lib.p_o | grep SqlTimestamp
00000000000002e8 D subprojectzm0zi0zi0zmCyhNFAzzUqYZZERicaukkM8G_Lib_zdfPersistFieldSqlTimestamp_closure
0000000000000240 D subprojectzm0zi0zi0zmCyhNFAzzUqYZZERicaukkM8G_Lib_zdfPersistFieldSqlTimestampzuzdcsqlType_closure
0000000000000028 T subprojectzm0zi0zi0zmCyhNFAzzUqYZZERicaukkM8G_Lib_zdfPersistFieldSqlTimestampzuzdcsqlType_info
When dumping the derived instances, the instance derived in the non-profiling version and the one derived in the profiling version are identical:
[2 of 3] Compiling Lib
==================== Derived instances ====================
Derived class instances:
instance Database.Persist.Class.PersistField.PersistField
Lib.Timestamp where
Database.Persist.Class.PersistField.toPersistValue
= GHC.Prim.coerce
@(GHC.Word.Word64 -> Database.Persist.Types.Base.PersistValue)
@(Lib.Timestamp -> Database.Persist.Types.Base.PersistValue)
(Database.Persist.Class.PersistField.toPersistValue
@GHC.Word.Word64) ::
Lib.Timestamp -> Database.Persist.Types.Base.PersistValue
Database.Persist.Class.PersistField.fromPersistValue
= GHC.Prim.coerce
@(Database.Persist.Types.Base.PersistValue
-> Data.Either.Either Data.Text.Internal.Text GHC.Word.Word64)
@(Database.Persist.Types.Base.PersistValue
-> Data.Either.Either Data.Text.Internal.Text Lib.Timestamp)
(Database.Persist.Class.PersistField.fromPersistValue
@GHC.Word.Word64) ::
Database.Persist.Types.Base.PersistValue
-> Data.Either.Either Data.Text.Internal.Text Lib.Timestamp
instance Database.Persist.Sql.Class.PersistFieldSql
Lib.Timestamp where
Database.Persist.Sql.Class.sqlType
= GHC.Prim.coerce
@(Data.Proxy.Proxy GHC.Word.Word64
-> Database.Persist.Types.Base.SqlType)
@(Data.Proxy.Proxy Lib.Timestamp
-> Database.Persist.Types.Base.SqlType)
(Database.Persist.Sql.Class.sqlType @GHC.Word.Word64) ::
Data.Proxy.Proxy Lib.Timestamp
-> Database.Persist.Types.Base.SqlType
Derived type family instances:
[3 of 3] Compiling Lib2 [Lib changed]
[2 of 3] Compiling Lib
==================== Derived instances ====================
Derived class instances:
instance Database.Persist.Class.PersistField.PersistField
Lib.Timestamp where
Database.Persist.Class.PersistField.toPersistValue
= GHC.Prim.coerce
@(GHC.Word.Word64 -> Database.Persist.Types.Base.PersistValue)
@(Lib.Timestamp -> Database.Persist.Types.Base.PersistValue)
(Database.Persist.Class.PersistField.toPersistValue
@GHC.Word.Word64) ::
Lib.Timestamp -> Database.Persist.Types.Base.PersistValue
Database.Persist.Class.PersistField.fromPersistValue
= GHC.Prim.coerce
@(Database.Persist.Types.Base.PersistValue
-> Data.Either.Either Data.Text.Internal.Text GHC.Word.Word64)
@(Database.Persist.Types.Base.PersistValue
-> Data.Either.Either Data.Text.Internal.Text Lib.Timestamp)
(Database.Persist.Class.PersistField.fromPersistValue
@GHC.Word.Word64) ::
Database.Persist.Types.Base.PersistValue
-> Data.Either.Either Data.Text.Internal.Text Lib.Timestamp
instance Database.Persist.Sql.Class.PersistFieldSql
Lib.Timestamp where
Database.Persist.Sql.Class.sqlType
= GHC.Prim.coerce
@(Data.Proxy.Proxy GHC.Word.Word64
-> Database.Persist.Types.Base.SqlType)
@(Data.Proxy.Proxy Lib.Timestamp
-> Database.Persist.Types.Base.SqlType)
(Database.Persist.Sql.Class.sqlType @GHC.Word.Word64) ::
Data.Proxy.Proxy Lib.Timestamp
-> Database.Persist.Types.Base.SqlType
Derived type family instances:
[3 of 3] Compiling Lib2 [Lib changed]
ghc: ^^ Could not load 'subprojectzm0zi0zi0zmCyhNFAzzUqYZZERicaukkM8G_Lib_zdfPersistFieldSqlTimestamp1_closure', dependency unresolved. See top entry above.
When building with cabal
, the profiling options are specified in a cabal.project
file as shown here:
profiling: True
library-profiling-detail: all-functions
Note that changing the library-profiling-detail
to top-level-functions
results in a successful profiling compilation using cabal and GHC 8.8.3.
Steps to reproduce
I attach here two simple minimal projects, one that fails and one that succeeds. They only differ in whether the instance is manually written or automatically derived. Running either stack build --profile
or cabal build
will throw the error in the buggy one.
Expected behavior
The output will show the error mentioned above and abort the compilation process.
Environment
- GHC version used:
- 8.8.3 using lts-16.0 resolver when building with stack.
- 8.8.3 installed on the system when building with cabal.
- 8.6.5 using lts-14.27 resolver shows the same error.
- Stack version:
Version 2.3.1, Git revision de2a7b694f07de7e6cf17f8c92338c16286b2878 (8103 commits) x86_64 hpack-0.33.0
- Cabal version:
cabal-install version 3.2.0.0 compiled using version 3.2.0.0 of the Cabal library