I am aware that there are already other questions on the topic, such as:
This one
This one
This other one
.. but hey, I am new to F# and still don't get it.
I have a F# project (thelibrary) which contains some modules. This project references in the solution explorer all the necessary libraries. Each .fs file opens the libraries used in the module. The F# project compiles properly.
I have then another F# project which contains a script. I reference thelibrary and the libraries used by thelibrary itself. In the script I reference with #r the dll with thelibrary and all the libraries used by thelibrary. I then open all the modules.
Intellisense says all is allright until I execute the script.
The script returns the error:
error FS0074: The type referenced through 'Fmat.Numerics.Matrix`2' is defined in an assembly that is not referenced. You must add a reference to assembly 'Fmat.Numerics'.
What is the procedure to hack this problem? How do I proceed from there?
I am interested is a solution to this specific problem but, as well, a cookbook recipe to fix this type of issues that have been quite a source of frustration for me.
Thank you.
The behavior of F# Interactive can be a bit odd in this case. In general, I think that things work better when you use #I to include the path with referenced assemblies in the resolution context and then reference the libraries by name using #r. So if you have a library Fmat.Numerics.dll in a folder C:\libs and it references another library another.dll then you can do:
#I "C:\\libs"
#r "another.dll"
#r "Fmat.Numerics.dll`
The first line means that F# Interactive will automatically look in the folder with your libraries (this can be relative path to your script location too) - as a result, the next two lines can just reference the libraries by their file names.
This is still a problem. I can also reproduce and fix the problem as follows:
I have three projects:
Informedica.Settings.Library
Informedica.Settings.Services.Interfaces
Informedica.Settings.Services.Models
Project 2 uses project 1 and project 3. Project 1 uses project 3.
When I load the references in the order (first proj 3 then proj 1):
#r #"..\..\Informedica.Settings.Services.Models\bin\Release\Informedica.Settings.Services.Models.dll"
#r #"..\..\Informedica.Settings.Library\bin\Release\Informedica.Settings.Library.dll"
Everything works. Unfortunately, when I use the VS2013 send references to fsi or use the new power tools generate references option, the order is:
#r #"..\..\Informedica.Settings.Library\bin\Release\Informedica.Settings.Library.dll"
#r #"..\..\Informedica.Settings.Services.Models\bin\Release\Informedica.Settings.Services.Models.dll"
This will result in the FS0074 error. Apparently, because a type from Services.Models is used in Settings.Library and the order of reference is reversed, fsi cannot handle this. Correcting the order of referencing solves the problem.
Running things in fsi does not add references from the project, you need to use #r .... The error message is reasonably obvious in what you need to do - add a reference to Fmat.Numerics. It is also possible that you have such a reference, but that fsi is sensitive to the load order.
Related
I have a legacy Windows project using the legacy 32 Bit C++ compiler. For various reasons I need to use the Windows 8+ function PathCchCanonicalizeEx. C++Builder seems to provide the header and some module definition file for that, but I can't find any library to link against:
[ilink32 Error] Error: Unresolved external 'PathCchCanonicalizeEx' referenced from C:\[...]\WIN32\DEBUG\TMP\FILE.OBJ
How am I supposed to fix this? Do I need to add a Windows 8.1 SDK? Is the necessary lib simply named differently and I can't find it? Something completely different?
According my tests, one has two options:
IMPLIB/MKEXP
I'm developing/testing a some Windows 10 21H2, which provides an implementation for PathCchCanonicalizeEx in some DLL already. So if that source DLL is known, one can use IMPLIB or MKEXP to create an import library manually. I did that and after adding the created library from IMPLIB to my project, the linker errors were instantly gone.
Though, it's not that easy to know where PathCchCanonicalizeEx is placed in. One pretty easily finds the api-ms-win-core-path-l1-1-0.dll, but that thing is NOT an actual file on the disk and therefore can't be used by IMPLIB or MKEXP. That name is only a virtual concept for the library loader to address the same named API set of modern Windows, the extension .dll doesn't mean it's a file at all.
You can use an API set name in the context of a loader operation such as LoadLibrary or P/Invoke instead of a DLL module name to ensure a correct route to the implementation no matter where the API is actually implemented on the current device. However, when you do this you must append the string .dll at the end of the contract name. This is a requirement of the loader to function properly, and is not considered actually a part of the contract name. Although contract names appear similar to DLL names in this context, they are fundamentally different from DLL module names and do not directly refer to a file on disk.
https://learn.microsoft.com/en-us/windows/win32/apiindex/windows-apisets#api-set-contract-names
What you really need to work with is KernelBase.dll, which is even documented by MS.
implib "KernelBase x86.lib" C:\Windows\SysWOW64\KernelBase.dll
implib "KernelBase x86-64.lib" C:\Windows\System32\KernelBase.dll
Module Definition File
The downside of manually creating LIB files is that one needs to maintain those with the project. Things depend on if the target is 32 or 64 Bit, DEBUG or RELEASE, so paths might become a bit complex, one might need to create relative paths for libraries in the project settings using placeholders for the target and stuff like that.
It seems that all of this can be avoided with Module Definition Files, which's purpose is to provide IMPORT and EXPORT statements to either consume exported functions by other DLLs or make that possible for others with own functions. I've successfully resolved my linker problems by simply creating a file named like my app using the extension .def alongside my other project files. That file needs to be added to the project, though.
dbxml.cbproj
dbxml.cbproj.local
dbxml.cpp
dbxml.def
dbxml.res
[...]
The following content made the app use the correct function from the correct DLL. Though, what didn't work was using the API set name, which resulted in an error message by the linker.
IMPORTS
KernelBase.PathCchCanonicalizeEx
IMPORTS
api-ms-win-core-path-l1-1-0.PathCchCanonicalizeEx
[ilink32 Error] Invalid command line switch for "ilink32". Parameter "ItemSpec" cannot be null.
[ilink32 Error] Fatal: Error processing .DEF file
The latter is after restarting C++Builder, so I guess the format of the file is simply wrong because of the API set name.
Is there a way to share types across fsx files?
When using #load to load the same file containing a type from multiple FSX files they seem to be prefixed into a different FS_00xx namespace each time, which means you can't pass them around.
Are there any ways around this behaviour without resorting to compiling into an assembly?
As for
http://msdn.microsoft.com/en-us/library/dd233169.aspx
[.fsx files are] used to include informal testing code in F# without adding the test code to your application, and without creating a separate project for it. By default, script files are not included in the build of a project even when they are part of a project.
This means that if you have a project with enough structure to be having such dependency problems, you should not use .fsx files, instead write modules/namespaces using .fs files. That is, you really should compile them types into an assembly.
The f# interactive interpreter generates assembly for each loaded files. If you load a file twice, the bytecode is generated twice, and the types are different even if they have the same definition and the same name. This means that there is no way for you to share types between two .fsx files, unless one of them includes the other.
When you #load a file which has the same types as ones already present in your environment, the f# interactive interpreter can use two different strategy:
refuse to load the file if conflicts with existing names arises (complaining that some stuff is already defined)
put the names in FS_00xx namespace (so that they are actually different types from the ones you already loaded), eventually opening the resulting namespace so that names are available from interactive session.
Since fsx files are supposed to be used as informal test it is more user-friendly to use the second approach (there are also technical reason for which the second approach is used, mainly dependent on .net VM type system, and the fact that existing types cannot be changed at runtime).
[Note: This is a more specific answer to a more specific question that is a duplicate of this one.]
I don't think there is a nice and easy solution for this. The one solution I have been using in some projects (like the F# snippets web site) is to have only one top-level fsx file that loads a number of fs files. For example, see app.fsx.
So, you would have common.fs, intMapper.fs and stringMapper.fs that would be loaded from caller.fsx as follows:
#load "common.fs"
#load "stringMapper.fs"
#load "intMapper.fs"
open Common
Inside stringMapper.fs and intMapper.fs, you do not load common.fs. The common types will be loaded by caller.fsx before, so things will work.
The only issue with this is that intMapper.fs now isn't a standalone script file - and if you want to get autocomplete in an editor, you need to add a fsproj file that specifies the file order. In F# snippets project, there is a project file which specifies the order in whch the editor should see and load the files.
Have all the #load and #open directives in the file you actually run from fsi.exe (C in the example below), and make sure the loaded files themselves do not #load their own dependencies:
Files A.fsx, B.fsx, C.fsx. B depends on A. C depends on B and A.
B contains
//adding the code below would cause the types defined in A to be loaded twice
//#load "A.fsx"
//#open A
C contains
#load "A.fsx"
#open A
#load "B.fsx"
#open B
Unfortunately this then makes all the files hard to edit from Visual Studio - the editor doesn't know about their dependencies and shows all sorts of errors.
Therefore this is a bit of a hack, and the recommended way seems to be to have a single .fsx file and compile everything else into a .dll :
// file1.fsx
#r "MyAssembly.dll"
https://msdn.microsoft.com/en-us/library/dd233175.aspx
Delphi 10 Seattle introduces Winapi.Security.pas. The project (a package) I'm trying to upgrade already has a Security.pas file. Short of removing Winapi from the list of scope names for the project (huge undesirable ripple effect), is there a way to tell the IDE and compiler to use the project's Security.pas file instead of Winapi.Security.pas?
I already tried renaming the projects Security.pas, but that caused even more problems with the compiler generating errors that have nothing to do with the code it was complaining about, so that's a rathole I'd rather not go down right now. This project builds just fine unchanged in XE7, FWIW, so this isn't due to any code changes in the project.
Updates:
Renaming the file and using a unit alias doesn't work.
The compiler behavior for a package differs from an application.
Looks like this might actually be related to the Winapi.Security unit rather than something as generic as you suggest in the question. For instance, the following package compiles just fine:
package Package1;
requires
rtl;
contains
Windows in 'Windows.pas'; // blank unit named Windows.pas in project folder
end.
Note that I have, like you, included Winapi in the project's list of unit scope names.
On the other hand, this package does not compile:
package Package1;
requires
rtl;
contains
Security in 'Security.pas'; // blank unit named Security.pas in project folder
end.
The compiler fails with:
[dcc32 Error] Package1.dpk(7): E2200 Package 'rtl' already contains unit 'Winapi.Security'
If the issue was purely related to unit scope names then either both packages would compile, or both would fail. Hence my conclusion that there is something out of whack with Winapi.Security.
I can find no source code for Winapi.Security. I wonder what it actually is. [Nicholas Ring located the source for me, inside the rtl\win\winrt directory.]
Anyway, I think it's time to submit a QP report. The package below that fails to compile is probably the starting point for that QP report. [Your submitted report is here RSP-12469.]
It seems clear to me that in the short term you must rename your unit if you wish to adopt Seattle.
FWIW, here are some other units that behave the same way as Winapi.Security:
Winapi.ApplicationModel
Winapi.CommonTypes
Winapi.Devices
Winapi.Foundation
Winapi.Gaming
Winapi.Globalization
Winapi.GraphicsRT
Winapi.Management
Winapi.Media
Winapi.Networking
Winapi.Storage
Winapi.UI
Winapi.WebRT
These are all newly added WinRT units which I expect is important.
If you put both Winapi.Security and your local Security in the same uses clause then you are able to access the members of both of them without issue. If you put them in separate uses clauses (Interface vs. Implementation) then you will get the error:
E2004 Identifier redeclared: 'Winapi.Security'
If I only include Security.pas in the uses clause (and it is included in the project) then it accesses its members just fine.
Perhaps I need more information about what error you are running into? I'll send you a sample project that shows this working.
I might well be wrong, but I believe that if Security.pas is in the uses clause of the dpr file, along with its full path, it will be preferred over whichever file can be found via the namespaces and search paths.
Open project settings, in the Delphi Compiler section remove "Winapi" from "Unit scope names".
This way, when you need the Security unit shipped with Delphi, you'll have to write Winapi.Security, and if you write Security, it will use your custom Security unit.
I have two projects in an F# solution.
1. main project with [EntryPoint] and set as the StarUp project.
2. support, the second project, holds a group of support modules. I.e. they are only called and never initiate anything nor serve as the entry point nor are the StartUp project.
For the last module in the support project, compiling in Visual Studio gives
warning FS0988: Main module of program is empty; nothing will happen
when it is run
While using compiler option nowarn inline as #nowarn "988" in the module causing the warning does suppress the message I would rather add something like a dummy function with comments that resolves the issue.
How does one make such a dummy function to resolve the warning?
EDIT
Jack is correct in that my support project was setup as a Console Application instead of a Class Library. Changing to Class Library resolved the warning. It is also nice to know about do () for the other case.
EDIT
While it seemed odd that I would have set a support project as a Console Application, I recently found that for some reason when I made a change to the code in the project, something changed the Output type from Class Library to Console Application. I suspect it has to do with the F# PowerPack and it's build rules, but it's only a guess.
Are you building the support project as a Library or as a Console Application? (This is set via the project properties page.)
If you're building it as a library, then you may need to add a do() at the end of the last file in the project. This is necessary to make the F# compiler happy in a few specific scenarios, like when you create a module which contains only assembly-level attributes (because they're applied to the assembly, the module appears "empty" to the compiler).
You can see an example in my code here:
https://github.com/jack-pappas/FSharp.Compatibility/blob/master/FSharp.Compatibility.OCaml/AssemblyInfo.fs
I'm currently porting a rather big project from C++ Builder 5 to the newest version, C++ Builder XE. It's my first experience with C++ Builder. I'm stuck with an error in a file, but I don't want to include this file anyway (it's code of a component not required anymore). I was not able to find out where and how this file is included, however. The compiler error does not give any hint at all apart from the error itself. How do you usually find out where a file is included?
The preprocessor is perfect for this. Right click on the cpp file which gives you the error in the project manager then choose "preprocess"
The output from this tells you every file and line number in the order they are processed. You can then search for the file in question, and the line above it is the file that included it.
This could conceivably be another header file as well, so it could be a long chain, but you can determine exactly where it comes from.
In the Project Options, enable the compiler's general messages. When the compiler encounters an error, you will be able to see the chain of includes that lead to the erroneous code.
If the files in question are rather sizable, a tool like Doxygen can be helpful in showing you the include dependencies (as well as call paths, etc.).
If it's just once or twice you'll have to do this, David Dean's suggestion of the preprocessor is golden.