I saw recently that some code (Fake, specifically) uses a function ## without defining it, presumeably it exists as part of the F# standard library, or somewhere else in .NET.
How do I search online for this type? Is there a pursuit-like or hoogle-like database I can use?
This question focuses more on how to find a particular function, and incidentally, hoogle alternatives. There are two very good answers, and the nature of the answers and comments are quite different.
There is FSDN that allows hoogle-like searching in mscorlib, some System.* dlls and a few libraries (including FAKE).
Update 2022-06-11: FSDN seems to be offline. I don’t know an alternative.
It's defined under Fake.EnvironmentHelper module (source):
let inline (##) path1 path2 = combinePaths path1 path2
where combinePaths is just a curried form of the BCL's Path.Combine with removal to leading path seperator in path2 (source):
let inline combinePaths path1 (path2 : string) =
Path.Combine(path1, path2.TrimStart [| '\\'; '/' |])
Note that Fake.EnvironmentHelper has the AutoOpenAttribute applied to it. Other modules referring to this ## operator do not need to explicitly open the Fake.EnvironmentHelper module.
Related
In LibreOffice, It is possible to run python scripts like this:
sURL = "vnd.sun.star.script:file.function?language=Python&location=document"
oScript = scriptProv.getScript(sURL)
x = oScript.Invoke(args, Array(), Array())
In that example 'file' is a filename, and 'function' is the name of a function in that file.
Is it possible to embed script in that URL? sURL="vnd.." & scriptblock & "?language.."
(It seems like the kind of thing that might be possible with the correct URL, or might not be possible if just not supported).
We can use Python's eval() function. Here is an example inspired by JohnSUN's explanation in the discussion. Note: xray() uses XrayTool to show output, but you could replace that line with any output method of your choosing, such as writing to a file.
def runArbitraryCode(*args):
url = args[0]
codeString = url.split("&codeToRun=")[1]
x = eval(codeString)
xray(x)
Now enter this formula in Calc and Ctrl+click on it.
=HYPERLINK("vnd.sun.star.script:misc_examples.py$runArbitraryCode?language=Python&location=user&codeToRun=5+1")
Result: 6
Obligatory caveat: Running eval() on an unknown string is about the worst idea imaginable in terms of security. So hopefully you're the one controlling the URL and not some black hat hacker!
I have a code analysis tool that I'd like to run for each cc_library (and cc_binary, silently implied for rest of the question). The tool has a CLI interfaces taking:
A tool project file
Compiler specifics, such as type sizes, built-ins, macros etc.
Files to analyze
File path, includes, defines
Rules to (not) apply
Files to add to the project
Options for synchronizing files with build data
JSON compilation database
Parse build log
Analyze and generate analysis report
I've been looking at how to integrate this in Bazel so that the files to analyze AND the associated includes and defines are updated automatically, and that any analysis result is properly cached. Generating JSON compilation database (using third party lib) or parsing build log both requires separate runs and updating the source tree. For this question I consider that a workaround I'm trying to remove.
What I've tried so far is using aspects, adding an analysis aspect to any library. The general idea is having a base project file holding library invariant configuration, appended with the cc_library files to analysis, and finally an analysis is triggered generating the report. But I'm having trouble to execute, and I'm not sure it's even possible.
This is my aspect implementation so far, trying to iterate through cc_library attributes and target compilation context:
def _print_aspect_impl(target, ctx):
# Make sure the rule has a srcs attribute
if hasattr(ctx.rule.attr, 'srcs'):
# Iterate through the files
for src in ctx.rule.attr.srcs:
for f in src.files.to_list():
if f.path.endswith(".c"):
print("file: ")
print(f.path)
print("includes: ")
print(target[CcInfo].compilation_context.includes)
print("quote_includes: ")
print(target[CcInfo].compilation_context.quote_includes)
print("system_includes: ")
print(target[CcInfo].compilation_context.system_includes)
print("define: " + define)
print(ctx.rule.attr.defines)
print("local_defines: ")
print(ctx.rule.attr.local_defines)
print("") # empty line to separate file prints
return []
What I cannot figure out is how to get ALL includes and defines used when compiling the library:
From libraries depended upon, recursively
copts, defines, includes
From the toolchain
features, cxx_builtin_include_directories
Questions:
How do I get the missing flags, continuing on presented technique?
Can I somehow retrieve the compile action command string?
Appended to analysis project using the build log API
Some other solution entirely?
Perhaps there is something one can do with cc_toolchain instead of aspects...
Aspects are the right tool to do that. The information you're looking for is contained in the providers, fragments, and toolchains of the cc_* rules the aspect has access to. Specifically, CcInfo has the target-specific pieces, the cpp fragment has the pieces configured from the command-line flag, and CcToolchainInfo has the parts from the toolchain.
CcInfo in target tells you if the current target has that provider, and target[CcInfo] accesses it.
The rules_cc my_c_compile example is where I usually look for pulling out a complete compiler command based on a CcInfo. Something like this should work from the aspect:
load("#rules_cc//cc:action_names.bzl", "C_COMPILE_ACTION_NAME")
load("#rules_cc//cc:toolchain_utils.bzl", "find_cpp_toolchain")
[in the impl]:
cc_toolchain = find_cpp_toolchain(ctx)
feature_configuration = cc_common.configure_features(
ctx = ctx,
cc_toolchain = cc_toolchain,
requested_features = ctx.features,
unsupported_features = ctx.disabled_features,
)
c_compiler_path = cc_common.get_tool_for_action(
feature_configuration = feature_configuration,
action_name = C_COMPILE_ACTION_NAME,
)
[in the loop]
c_compile_variables = cc_common.create_compile_variables(
feature_configuration = feature_configuration,
cc_toolchain = cc_toolchain,
user_compile_flags = ctx.fragments.cpp.copts + ctx.fragments.cpp.conlyopts,
source_file = src.path,
)
command_line = cc_common.get_memory_inefficient_command_line(
feature_configuration = feature_configuration,
action_name = C_COMPILE_ACTION_NAME,
variables = c_compile_variables,
)
env = cc_common.get_environment_variables(
feature_configuration = feature_configuration,
action_name = C_COMPILE_ACTION_NAME,
variables = c_compile_variables,
)
That example only handles C files (not C++), you'll have to change the action names and which parts of the fragment it uses appropriately.
You have to add toolchains = ["#bazel_tools//tools/cpp:toolchain_type"] and fragments = ["cpp"] to the aspect invocation to use those. Also see the note in find_cc_toolchain.bzl about the _cc_toolchain attr if you're using legacy toolchain resolution.
The information coming from the rules and the toolchain is already structured. Depending on what your analysis tool wants, it might make more sense to extract it directly instead of generating a full command line. Most of the provider, fragment, and toolchain is well-documented if you want to look at those directly.
You might pass required_providers = [CcInfo] to aspect to limit propagation to rules which include it, depending on how you want to manage propagation of your aspect.
The Integrating with C++ Rules documentation page also has some more info.
I have the pie file which is used for inference in GraphDB ontotext. I have written the ruleset correctly. while uploading the file it seems ok. But, while creating the repository, it is showing the “Invalid Ruleset file. Please upload valid one” I think the issue is related to the hidden character present inside the file. How to get out if such characters. My file content is :
Prefices
{
rdf : http://www.w3.org/1999/02/22-rdf-syntax-ns#
owl : http://www.w3.org/2002/07/owl#
abc : http://www.xyzabc.com/schema/abcentity#
}
Axioms
{
<abc:isLocatedIn> <rdf:type> <owl:ObjectProperty>
}
Rules
{
Id: isLocatedInHierarchy
a <abc:isLocatedIn> b [Constraint a != b]
b <abc:isLocatedIn> c [Constraint b != c]
a <abc:isLocatedIn> c [Constraint a != c]
}
hidden character present inside the file
Do you mean a Unicode BOM mark? Get an editor that can save without such mark (I strongly recommend Akelpad: http://akelpad.sourceforge.net/), or just save in ASCII.
BTW, writing PIE files with per-property rules is not a good idea. Instead, use a generic rule for transitive property and then declare abc:isLocatedIn transitive in your ontology. The cheapest builtin in which such rule is included is rdfsPlus-optimized. If you select it, then you add to your ontology
abc:isLocatedIn a owl:TransitiveProperty.
However, it's a better idea to keep a "step" property abc:isLocatedIn and then a transitive property on top of it, eg abc:isLocatedTransitive:
abc:isLocatedTransitive a owl:TransitiveProperty.
abc:isLocatedIn rdfs:subPropertyOf abc:isLocatedTransitive.
Finally, there's a more efficient way to compute the transitive closure, see http://rawgit2.com/VladimirAlexiev/my/master/pubs/extending-owl2/index.html#sec-3-1:
abc:isLocatedTransitive ptop:transitiveOver abc:isLocatedIn.
abc:isLocatedIn rdfs:subPropertyOf abc:isLocatedTransitive.
I was also been able to upload successfully your .pie file. Maybe the issue is related to the computer locale or something in the environment. If you are using Windows Notepad++ seems like a logical choice. I guess there is an option to view all the hidden characters, but I've never used it. If you are using Linux there are plenty of choices, even included one like vim or nano which will work just fine.
In order to create a Json provider I need to pass a literal with the path. There are several people working on the project from different locations, and the paths are different in each case. (Actually only the beginning of each path). I tried to create a literal with pattern matching but the compiler does not accept it. Is there another way to do this?
My failed attempt is below:
open FSharp.Data
[<Literal>]
let bitbucketRoot = // Error message: This is not a valid constant expression
let computerName = Environment.MachineName
match computerName with
| "DESKTOP-G3OF32U" -> "C:\\Users\\Fernando"
| "HPW8" -> #"H:\Dropbox\"
| _ -> failwith "Unknown computer"
[<Literal>] // Error message: This is not a valid constant expression
let projDataPath = bitbucketRoot + #"Bitbucket\VSProjects\Fractal10\Fractal10\data\"
[<Literal>] // Error message: This is not a valid constant expression
let jsonPath = projDataPath + "fractal.json"
type PathInfo = JsonProvider<Sample=jsonPath>
I would advise that you store it in source control and make it a path relative to your project root, assuming you are working out of a common source control repository.
Either that, or host the sample on a public URL. (I wouldn't actually recommend this because including it in your source repository allows versioning and doesn't publicly expose your data)
You cannot create a conditional literal as the other comments point it out. However this is a fairly frequent use case and the way to deal with it is as follows:
#r #"..\packages\FSharp.Data\lib\net40\FSharp.Data.dll"
open FSharp.Data
open System
open System.IO
[<Literal>]
let JsonSource = __SOURCE_DIRECTORY__ + #"\test.json"
type JSonType = JsonProvider<JsonSource>
let json1 = JSonType.GetSamples()
let anotherPath = #"C:\tmp"
let anotherJson = anotherPath + #"\test.json"
let json2 = JSonType.Load(anotherJson)
The __SOURCE_DIRECTORY__ directive will point to the project root (just display it in the REPL) and then you can add the filename to it and make that a literal. If you check in this file into a git repo, then everyone who checks it out can have it in a relative path, and you can refer it when generating the type. When actually using the type or referring to the full file you can just use the .Load() method to load any file, and this doesn't have to be a literal.
There is actually a second way, which could work for you depending on the circumstances, compile a sample, and distribute it as a .dll. You can refer to this and use it directly without having access to the actual file. Please see the Using the JSON Provider in a Library section at the end of the documentation.
I have not tried referring to the json in a config file, it might also be possible.
How do I pass a variable path to a type provider?
I have a file that I want to load using the SAS type provider that is in different locations on different PCs.
For example, I would like to do something like:
[<Literal>]
let saspath =
match System.Environment.MachineName with
| "a" -> "c:/sas.sas7bdat"
| "b" -> "d:/sas.sas7bdat"
let sasfile = new SasFileTypeProvider<saspath>()
But this is not valid. It's related to this Type provider and static argument in F# and For an F# Type Provider, how do I make a relative path work as a static parameter?, but I do not have the option of using relative paths.
Unfortunately, this is not easily possible. Parameters passed to type providers have to be (syntactically) constants. There are various workarounds.
Use relative path. Can you change the code to use a relative path that will always work? This would be ideal - assuming the type provider supports this.
Improve the type provider. You could send a PR to the SAS type provider so that it can take the file name from an local config file or and environment variable. Many of the SQL type providers do this, because it is a good solution if you need some configuration.
Generate file with a constant. This is a bit of a hack, but you can generate a separate fsx file with the constant and #load it. You'll get red squigglies in the rest of your code (until you run the first part of the script), but if you're happy with that:
open System.IO
let text =
match System.Environment.MachineName with
| "a" -> "module Constants\n[<Literal>] let path = \"c:/sas.sas7bdat\""
| "b" -> "module Constants\n[<Literal>] let path = \"c:/sas.sas7bdat\""
File.WriteAllText("C:/temp/constants.fsx", text)
;;
#load "C:/temp/constants.fsx"
let sasfile = new SasFileTypeProvider<Constants.path>()