I'd like to write a plugin for some Windows application, and it must be a DLL. I'd really love to try doing it in a mix of Red & Red/System. But asking on Rebol&Red chatroom here on SO, I got mixed responses as to whether it is currently possible in both Red and Red/System, or in Red/System only. What's the definitive answer?
Yes, it is possible. You can check the announcement on the Red-Blog for 0.3.3
First of all, here is a short snippet describing the process for Red/System:
Shared lib generation
Since a year, we were working on bringing shared library generation,
now it is available in the main branch. New features were added to
support library generation like a way to declare the exported symbols
and special callback functions when loading and freeing the library.
Here is a simple example of a Red/System library:
Red/System [
File: %testlib.reds
]
inc: func [n [integer!] return: [integer!]][n + 1]
#export [inc]
You compile such shared library using the new -dlib command-line
option:
do/args %rsc.r "-dlib testlib.reds"
The output binary name will have a platform-specifc suffix (.dll, .so
or .dylib).
Secondly, I was finally able to get a single simple Red script to compile to a .dll. The #export directive needs to be in a Red/System context as you can see the #system-global directive provides. Any function you have in Red needs to be wrapped with a Red/System wrapper. You can do this using #call as done below:
Red []
hello: does [print "hello"]
#system-global [
hellosystem: does [
#call [hello]
]
#export cdecl [hellosystem]
]
Related
As I can see read is not native
>> native? :read
== false
but when I tried to get the source code with
write-clipboard mold :read
I only got header of read
make action! [[
"Reads from a file, URL, or other port"
source [file! url!]
/part {Partial read a given number of units (source relative)}
length [number!]
/seek "Read from a specific position (source relative)"
index [number!]
/binary "Preserves contents exactly"
/lines "Convert to block of strings"
/info
/as {Read with the specified encoding, default is 'UTF-8}
encoding [word!]
]]
Can I get the rest body somehow ?
The source code of native! and action! values is written in Red/System and part of the low-level runtime library code. They are not implemented in Red itself for sake of performance or because they require access to low-level features not available at Red level. Natives source code have a single entry point which you can find in the runtime/natives.reds file. For actions, it is more complex as they delegate their implementation to each datatype. Actions are basically methods for the datatype classes.
I have a Modelica file that references c code during simulation through an external library *.a file.
For example:
model CallAdd
input Real FirstInput(start=0);
input Real SecondInput(start=0);
output Real FMUOutput(start=0);
function CAdd
input Real x(start=0);
input Real y(start=0);
output Real z(start=0);
external "C" annotation(Library = "CAdd", LibraryDirectory = "modelica://CallAdd");
end CAdd;
equation
FMUOutput = CAdd(FirstInput,SecondInput);
annotation(uses(Modelica(version = "3.2.1")));
end CallAdd;
When opening the Modelica model in OpenModelica the required files appear to be automatically loaded because it simulates and gives appropriate results.
However, when I try to compile the Modelica file with JModelica-SDK-1.12 I receive an error that the library *.a file could not be found.
So my question is: What is the proper way to reference additional files when using compile_fmu in JModelica?
With no success, I've tried:
# Import the compiler function
from pymodelica import compile_fmu
model_name = "CallAdd"
mo_file = "CallAdd.mo"
# Compile the model and save the return argument, for use later if wanted
my_fmu = compile_fmu(model_name, mo_file, target="cs",compiler_options = {'extra_lib_dirs':'C:/ToFolderContainingLib/'})
The strange thing is that when I was using JModelica-1.17 (non-SDK) the file compiled fine but the results didn't make sense. I was recommended to try the SDK version to see if it fixed my errors in my previous post here.
Try positioning the external library in sub-folder named as the platform your currently on. So in your example, I'd position the library (libCAdd.a) in sub-folder named linux64, as I'm on a 64bit Linux machine and then run the code.
If is a small piece of C code, as a last alternative you could try to include the C file directly in the Modelica code:
external "C" annotation(Include="
// the entire C code here
");
Hopefully the JModelica people will give you a better answer soon.
You could try to ask this on their website also:
http://www.jmodelica.org/forum
Here's what I'm currently using, which I think gets the job done, but there's got to be a better way:
func isWindows() bool {
return os.PathSeparator == '\\' && os.PathListSeparator == ';'
}
As you can see, in my case all I need to know is how to detect windows but I'd like to know the way to detect any platform/os.
Play:
http://play.golang.org/p/r4lYWDJDxL
Detection at compile time
If you're doing this to have different implementations depending on the OS, it is more useful to
have separate files with the implementation of that feature and add build tags to each
of the files. This is used in many places in the standard library, for example in the os package.
These so-called "Build constraints" or "Build tags" are explained here.
Say you have the constant PATH_SEPARATOR and you want that platform-dependent, you
would make two files, one for Windows and one for the (UNIX) rest:
/project/path_windows.go
/project/path_unix.go
The code of these files would then be:
path_windows.go
// +build windows
package project
const PATH_SEPARATOR = '\\'
path_unix.go
// +build !windows
package project
const PATH_SEPARATOR = '/'
You can now access PATH_SEPARATOR in your code and have it platform dependant.
Detection at runtime
If you want to determine the operating system at runtime, use the runtime.GOOS
variable:
if runtime.GOOS == "windows" {
fmt.Println("Hello from Windows")
}
While this is compiled into the runtime and therefore ignores the environment,
you can nevertheless be relatively certain that the value is correct.
The reason for this is that every platform that is worth distinguishing needs
rebuilding due to different executable formats and thus has a new GOOS value.
Have you looked at the runtime package? It has a GOOS const: http://golang.org/pkg/runtime/#pkg-constants
It's 2022 and the correct answer for go 1.18+ is:
At runtime you want:
if runtime.GOOS == "windows" {
// windows specific code here...
}
If you need to determine the filesystem path separator character
Use: os.PathSeparator
Examples:
c:\program files
/usr/local/bin
If you need the Path List separator as used by the PATH environment variable
Use: os.PathListSeparator
Examples:
/usr/local/bin:/usr/local:
"C:\windows";"c:\windows\system32";
Since this is an older question and answer I have found another solution.
You could simply use the constants defined in the os package. This const returns a rune so you would need to use string conversion also.
string(os.PathSeparator)
string(os.PathListSeparator)
Example: https://play.golang.org/p/g6jnF7W5_pJ
I just stumbled on this looking for something else and noticed the age of this post so I'll add a more updated addition. If you're just trying to handle the correct filepath I would use filepath.Join(). Its takes all of the guesswork out of os issues. If there is more you need, other than just filepath, using the runtime constants (runtime.GOOS & runtime.GOARCH) are the way to go: playground example
I tested in Go 1.17.1 which really worked for me.
package main
import (
"fmt"
"runtime"
)
func main(){
fmt.Println(runtime.GOOS)
}
Output:
darwin
With regards to detecting the platform, you can use Distribution Detector project to detect the Linux distribution being run.
The first answer from #nemo is the most apropiate, i just wanted to point out that if you are currently a user of gopls language server the build tags may not work as intended.
There's no solution or workaround up to now, the most you can do is change your editor's lsp configs (vscode, neovim, emacs, etc) to select a build tag in order to being able to edit the files with that tag without errors.
Editing files with another tag will not work, and trying to select multiple tags fails as well.
This is the current progress of the issue github#go/x/tools/gopls
I've an application written using PyGTK (GTK+2). I'd like to integrate it with Nautilus via an extension (something I am trying to learn). My current desktop has GNOME3 and Nautilus 3, which is written in GTK+3 and the extensions for Nautilus uses PyGObject.
Can I integrate my application in GTK+2 with Nautilus 3? (without porting my application to GTK+3, yet). Any hint?
I'm planning to port my application to GTK+3 (PyGObject), but it'll require more time than I have now.
Yes, it is possible. For instance, you can use Nautilus to call your program with the files or directories as arguments. The program you are calling can be written with any toolkit, or even be just a shell script.
A tiny example or an extension:
from gi.repository import Nautilus, GObject
from urllib import unquote
PROGRAM_NAME = '/path/to/your/program'
class MyExtension(GObject.GObject, Nautilus.MenuProvider):
def __init__(self):
pass
def call_my_program(self, menu, files):
# Do whatever you want to do with the files selected
if len(files) == 0:
return
# Strip the URI format to plain file names
names = [ unquote(file.get_uri()[7:]) for file in files ]
argv = [ PROGRAM_NAME ] + names
GObject.spawn_async(argv, flags=GObject.SPAWN_SEARCH_PATH)
def get_file_items(self, window, files):
# Show the menu if there is at least on file selected
if len(files) == 0:
return
# We care only files (local files)
for fd in files:
if fd.is_directory() or fd.get_uri_scheme() != 'file':
return
item = Nautilus.MenuItem(name='MyExtensionID::MyMethodID',
label='Do something with my program...')
item.connect('activate', self.call_my_program, files)
return item,
The extension is written using GObject Introspection (Nautilus 3), and it is generic: you can call any external program you want that accepts files as arguments. The key is GObject.spawn_async().
get_file_items is the method that Nautilus call when the user interacts with files. In that, you can bind a contextual menu (with Nautilus.MenuItem()). Then, you connect that menu with the method that calls your program (call_my_program()).
You can create other filters in the method get_file_items. For instance, to show the contextual menu only if there are text plain files selected (using fd.is_mime_type()). You can do whatever you have in mind. Beware of performing only non-blocking operations, otherwise you could block Nautilus.
To test the extension, you can install it in ~/.local/share/nautilus-python/extensions.
Check Introspection Porting:
Note that you can't do a migration halfway: If you try to import both
gtk and gi.repository.Gtk, you'll get nothing but program hangs and
crashes, as you are trying to work with the same library in two
different ways. You can mix static and GI bindings of different
libraries though, such as dbus-python and gi.repository.Gtk.
So, it depends on how the Nautilus plugins are implemented.
I want to implement the function like embedding the socket function in my Lua build.
So I don't need to copy socket.core.dll any more (just for fun).
I search the maillist, and see some guys discuss the topic,
http://lua-users.org/lists/lua-l/2005-10/msg00269.html
But I have question for the details steps, who could give me a detailed steps for changing the lua and luasocket code to make them work together (not with dll method).
I tried these steps in windows xp with VC2008:
1) copy luasocket code to Lua project.
2) add some code
static const luaL_Reg lualibs[] = {
{"", luaopen_base},
{LUA_LOADLIBNAME, luaopen_package},
{LUA_TABLIBNAME, luaopen_table},
{LUA_IOLIBNAME, luaopen_io},
{LUA_OSLIBNAME, luaopen_os},
{LUA_STRLIBNAME, luaopen_string},
{LUA_MATHLIBNAME, luaopen_math},
{LUA_DBLIBNAME, luaopen_debug},
{LUA_SOCKETLIBNAME, luaopen_socket_core}, // add this line
{LUA_MIMELIBNAME, luaopen_socket_core}, // add this line
{NULL, NULL}
};
3) build the project, and run it.
When I type print(socket._VERSION), it shows luasocket 2.0.2, it is correct.
When I type print(socket.dns.toip("localhost")), it shows 127.0.0.1 table: 00480AD0, it is correct too.
But when I try to use other features, for example bind, it can't work.
Who could tell me the reason?
you need put luasocket stuff into the package.preload table, in this way:
lua_getfield(L, LUA_GLOBALSINDEX, "package");
lua_getfield(L, -1, "preload");
lua_pushcfunction(L, luaopen_socket_core);
lua_setfield(L, -2, "socket.core");
// add mime.core yourself...
luasocket is a mixed C/lua module, you need to bundle both versions into your application if you want it to work without any extra files.
socket.lua loads socket.core (from socket/core.dll)
mime.lua loads mime.core (from mime/core.dll)
So in order for your application to work you will need to build all the .dll files and the .lua files into your application and manually load them (or set them up to be loaded correctly via custom package loaders).
The email you quoted is tweaking the package.preload table (in a way that appears a tad odd now but might work anyway) to get the built-in C code to be loaded correctly when require is called.
Try running
for k, v in pairs(socket) do print(k, v) end
and maybe we'll be able to help.