mirror of
https://github.com/rclone/rclone.git
synced 2024-11-25 09:41:44 +08:00
docs/librclone: document use from C/C++ on Windows
This commit is contained in:
parent
237daa8aaf
commit
2fed02211c
|
@ -4,13 +4,19 @@ This directory contains code to build rclone as a C library and the
|
||||||
shims for accessing rclone from C and other languages.
|
shims for accessing rclone from C and other languages.
|
||||||
|
|
||||||
**Note** for the moment, the interfaces defined here are experimental
|
**Note** for the moment, the interfaces defined here are experimental
|
||||||
and may change in the future. Eventually they will stabilse and this
|
and may change in the future. Eventually they will stabilise and this
|
||||||
notice will be removed.
|
notice will be removed.
|
||||||
|
|
||||||
## C
|
## C
|
||||||
|
|
||||||
The shims are a thin wrapper over the rclone RPC.
|
The shims are a thin wrapper over the rclone RPC.
|
||||||
|
|
||||||
|
The implementation is based on cgo; to build it you need Go and a GCC compatible
|
||||||
|
C compiler (GCC or Clang). On Windows you can use the MinGW port of GCC,
|
||||||
|
installing it via the [MSYS2](https://www.msys2.org) distribution is recommended
|
||||||
|
(make sure you install GCC in the classic mingw64 subsystem, the ucrt64 version
|
||||||
|
is not compatible with cgo).
|
||||||
|
|
||||||
Build a shared library like this:
|
Build a shared library like this:
|
||||||
|
|
||||||
go build --buildmode=c-shared -o librclone.so github.com/rclone/rclone/librclone
|
go build --buildmode=c-shared -o librclone.so github.com/rclone/rclone/librclone
|
||||||
|
@ -20,9 +26,12 @@ Build a static library like this:
|
||||||
go build --buildmode=c-archive -o librclone.a github.com/rclone/rclone/librclone
|
go build --buildmode=c-archive -o librclone.a github.com/rclone/rclone/librclone
|
||||||
|
|
||||||
Both the above commands will also generate `librclone.h` which should
|
Both the above commands will also generate `librclone.h` which should
|
||||||
be `#include`d in `C` programs wishing to use the library.
|
be `#include`d in `C` programs wishing to use the library (with some
|
||||||
|
[exceptions](#include-file)).
|
||||||
|
|
||||||
The library will depend on `libdl` and `libpthread`.
|
The library will depend on `libdl` and `libpthread` on Linux/macOS, unless
|
||||||
|
linking with a C standard library where their functionality is integrated,
|
||||||
|
which is the case for glibc version 2.34 and newer.
|
||||||
|
|
||||||
### Documentation
|
### Documentation
|
||||||
|
|
||||||
|
@ -33,9 +42,114 @@ For documentation see the Go documentation for:
|
||||||
- [RcloneRPC](https://pkg.go.dev/github.com/rclone/rclone/librclone#RcloneRPC)
|
- [RcloneRPC](https://pkg.go.dev/github.com/rclone/rclone/librclone#RcloneRPC)
|
||||||
- [RcloneFreeString](https://pkg.go.dev/github.com/rclone/rclone/librclone#RcloneFreeString)
|
- [RcloneFreeString](https://pkg.go.dev/github.com/rclone/rclone/librclone#RcloneFreeString)
|
||||||
|
|
||||||
### C Example
|
### Linux C example
|
||||||
|
|
||||||
There is an example program `ctest.c` with `Makefile` in the `ctest` subdirectory.
|
There is an example program `ctest.c`, with `Makefile`, in the `ctest`
|
||||||
|
subdirectory. It can be built on Linux/macOS, but not Windows without
|
||||||
|
changes - as described next.
|
||||||
|
|
||||||
|
### Windows C/C++ guidelines
|
||||||
|
|
||||||
|
The official [C example](#linux-c-example) is targeting Linux/macOS, and will
|
||||||
|
not work on Windows. It is very possible to use `librclone` from a C/C++
|
||||||
|
application on Windows, but there are some pitfalls that you can avoid by
|
||||||
|
following these guidelines:
|
||||||
|
- Build `librclone` as shared library, and use run-time dynamic linking (see [linking](#linking)).
|
||||||
|
- Do not try to unload the library with `FreeLibrary` (see [unloading](#unloading)).
|
||||||
|
- Deallocate returned strings with API function `RcloneFreeString` (see [memory management](#memory-management)).
|
||||||
|
- Define struct `RcloneRPCResult`, instead of including `librclone.h` (see [include file](#include-file)).
|
||||||
|
- Use UTF-8 encoded strings (see [encoding](#encoding)).
|
||||||
|
- Properly escape JSON strings, beware of the native path separator (see [escaping](#escaping)).
|
||||||
|
|
||||||
|
#### Linking
|
||||||
|
|
||||||
|
Use of different compilers, compiler versions, build configuration, and
|
||||||
|
dependency on different C runtime libraries for a library and the application
|
||||||
|
that references it, may easily break compatibility. When building the librclone
|
||||||
|
library with MinGW GCC compiler (via go build command), if you link it into an
|
||||||
|
application built with Visual C++ for example, there will be more than enough
|
||||||
|
differences to cause problems.
|
||||||
|
|
||||||
|
Linking with static library requires most compatibility, and is less likely to
|
||||||
|
work. Linking with shared library is therefore recommended. The library exposes
|
||||||
|
a plain C interface, and by using run-time dynamic linking (by using Windows API
|
||||||
|
functions `LoadLibrary` and `GetProcAddress`), you can make a boundary that
|
||||||
|
ensures compatibility (and in any case, you will not have an import library).
|
||||||
|
The only remaining concern is then memory allocations; you should make sure
|
||||||
|
memory is deallocated in the same library where it was allocated, as explained
|
||||||
|
[below](#memory-management).
|
||||||
|
|
||||||
|
#### Unloading
|
||||||
|
|
||||||
|
Do not try to unload the library with `FreeLibrary`, when using run-time dynamic
|
||||||
|
linking. The library includes Go-specific runtime components, with garbage
|
||||||
|
collection and other background threads, which do not handle unloading. Trying
|
||||||
|
to call `FreeLibrary` will crash the application. I.e. after you have loaded
|
||||||
|
`librclone.dll` into your application it must stay loaded until your application
|
||||||
|
exits.
|
||||||
|
|
||||||
|
#### Memory management
|
||||||
|
|
||||||
|
The output string returned from `RcloneRPC` is allocated within the `librclone`
|
||||||
|
library, and caller is responsible for freeing the memory. Due to C runtime
|
||||||
|
library differences, as mentioned [above](#linking), it is not recommended to do
|
||||||
|
this by calling `free` from the consuming application. You should instead use
|
||||||
|
the API function `RcloneFreeString`, which will call `free` from within the
|
||||||
|
`librclone` library, using the same runtime that allocated it in the first
|
||||||
|
place.
|
||||||
|
|
||||||
|
#### Include file
|
||||||
|
|
||||||
|
Do not include `librclone.h`. It contains some plain C, golang/cgo and GCC
|
||||||
|
specific type definitions that will not compile with all other compilers
|
||||||
|
without adjustments, where Visual C++ is one notable example. When using
|
||||||
|
run-time dynamic linking, you have no use of the extern declared functions
|
||||||
|
either.
|
||||||
|
|
||||||
|
The interface of librclone is so simple, that all you need is to define the
|
||||||
|
small struct `RcloneRPCResult`, from [librclone.go](librclone.go):
|
||||||
|
|
||||||
|
```C++
|
||||||
|
struct RcloneRPCResult {
|
||||||
|
char* Output;
|
||||||
|
int Status;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Encoding
|
||||||
|
|
||||||
|
The API uses plain C strings (type `char*`, called "narrow" strings), and rclone
|
||||||
|
assumes content is UTF-8 encoded. On Linux systems this normally matches the
|
||||||
|
standard string representation, and no special considerations must be made. On
|
||||||
|
Windows it is more complex.
|
||||||
|
|
||||||
|
On Windows, narrow strings are traditionally used with native non-Unicode
|
||||||
|
encoding, the so-called ANSI code page, while Unicode strings are instead
|
||||||
|
represented with the alternative `wchar_t*` type, called "wide" strings, and
|
||||||
|
encoded as UTF-16. This means, to correctly handle characters that are encoded
|
||||||
|
differently in UTF-8, you will need to perform conversion at some level:
|
||||||
|
Conversion between UTF-8 encoded narrow strings used by rclone, and either ANSI
|
||||||
|
encoded narrow strings or wide UTF-16 encoded strings used in runtime function,
|
||||||
|
Windows API, third party APIs, etc.
|
||||||
|
|
||||||
|
#### Escaping
|
||||||
|
|
||||||
|
The RPC method takes a string containing JSON. In addition to the normal
|
||||||
|
escaping of strings constants in your C/C++ source code, the JSON needs its
|
||||||
|
own escaping. This is not a Windows-specific issue, but there is the
|
||||||
|
additional challenge that native filesystem path separator is the same as
|
||||||
|
the escape character, and you may end up with strings like this:
|
||||||
|
|
||||||
|
```C++
|
||||||
|
const char* input = "{"
|
||||||
|
"\"fs\": \"C:\\\\Temp\","
|
||||||
|
"\"remote\": \"sub/folder\","
|
||||||
|
"\"opt\": \"{\\\"showHash\\\": true}\""
|
||||||
|
"}";
|
||||||
|
```
|
||||||
|
|
||||||
|
With C++11 you can use raw string literals to avoid the C++ escaping of string
|
||||||
|
constants, leaving escaping only necessary for the contained JSON.
|
||||||
|
|
||||||
## gomobile
|
## gomobile
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user