Upgrade rust/crates/libloading to 0.6.3 am: 32890e15d2 am: 1d3b6e97be am: 89555bed82

Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/libloading/+/1408804

Change-Id: Id12ca3e07dd7bbdb79e05c55de7a8dc1753fb6c8
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 7405439..a289ae4 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
 {
   "git": {
-    "sha1": "fa787a3be5a9a6dcc47425c7298fed5a16f06afe"
+    "sha1": "21c7cdb08ffc38ceb0b0f9e7038f88548c2ade94"
   }
 }
diff --git a/.github/workflows/libloading.yml b/.github/workflows/libloading.yml
index 2ba5d13..d315445 100644
--- a/.github/workflows/libloading.yml
+++ b/.github/workflows/libloading.yml
@@ -24,12 +24,17 @@
         with:
             toolchain: ${{ matrix.rust_toolchain }}
             profile: minimal
+            components: clippy
             default: true
       - name: Update
         uses: actions-rs/cargo@v1
         with:
           command: update
           args: --manifest-path=Cargo.toml
+      - name: Clippy
+        uses: actions-rs/cargo@v1
+        with:
+          command: clippy
       - name: Build
         uses: actions-rs/cargo@v1
         with:
@@ -45,6 +50,14 @@
         with:
           command: test
           args: --manifest-path=Cargo.toml --release -- --nocapture
+      - name: Documentation
+        uses: actions-rs/cargo@v1
+        with:
+          command: doc
+          args: --manifest-path=Cargo.toml
+        env:
+          RUSTDOCFLAGS: --cfg docsrs
+        if: ${{ matrix.rust_toolchain == 'nightly' }}
 
   windows-gnu-test:
     runs-on: windows-latest
@@ -54,10 +67,17 @@
         rust_toolchain: [nightly, stable]
         rust_target:
           - x86_64-pc-windows-gnu
-          # Only 64 bit GCC is preinstalled
-          #- i686-pc-windows-gnu
+          - i686-pc-windows-gnu
     steps:
       - uses: actions/checkout@v2
+      - name: Add MSYS2 to the PATH
+        run: echo "::add-path::c:/msys64/bin"
+      - name: Add 32-bit mingw-w64 to the PATH
+        run: echo "::add-path::c:/msys64/mingw32/bin"
+        if: startsWith(matrix.rust_target, 'i686')
+      - name: Add 64-bit mingw-w64 to the PATH
+        run: echo "::add-path::c:/msys64/mingw64/bin"
+        if: startsWith(matrix.rust_target, 'x86_64')
       - name: Install Rust nightly
         uses: actions-rs/toolchain@v1
         with:
@@ -65,13 +85,6 @@
             target: ${{ matrix.rust_target }}
             profile: minimal
             default: true
-      # https://github.com/rust-lang/rust/issues/49078
-      - name: Fix windows-gnu rust-mingw
-        run : |
-          for i in crt2.o dllcrt2.o libmingwex.a libmsvcrt.a ; do
-            cp -f "/C/ProgramData/Chocolatey/lib/mingw/tools/install/mingw64/x86_64-w64-mingw32/lib/$i" "`rustc --print sysroot`/lib/rustlib/x86_64-pc-windows-gnu/lib"
-          done
-        shell: bash
       - uses: actions-rs/cargo@v1
         with:
           command: build
diff --git a/Android.bp b/Android.bp
index b7f23ac..a40bc5a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -8,8 +8,14 @@
     flags: [
         "--cfg mtsafe_dlerror",
     ],
+    rustlibs: [
+        "libcfg_if",
+    ],
     // TODO: Cannot use libdl on Android host?
     // shared_libs: [
     //     "libdl",
     // ],
 }
+
+// dependent_library ["feature_list"]
+//   cfg-if-0.1.10
diff --git a/Cargo.toml b/Cargo.toml
index 630f1e7..41ad4e7 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,14 +12,26 @@
 
 [package]
 name = "libloading"
-version = "0.6.2"
+version = "0.6.3"
 authors = ["Simonas Kazlauskas <libloading@kazlauskas.me>"]
 build = "build.rs"
 description = "A safer binding to platform’s dynamic library loading utilities"
 documentation = "https://docs.rs/libloading/"
+readme = "README.mkd"
 keywords = ["dlopen", "load", "shared", "dylib"]
+categories = ["api-bindings"]
 license = "ISC"
 repository = "https://github.com/nagisa/rust_libloading/"
+[package.metadata.docs.rs]
+all-features = true
+rustdoc-args = ["--cfg", "docsrs"]
+[dev-dependencies.libc]
+version = "0.2"
+
+[dev-dependencies.static_assertions]
+version = "1.1"
+[target."cfg(unix)".dependencies.cfg-if]
+version = "0.1"
 [target."cfg(windows)".dependencies.winapi]
 version = "0.3"
 features = ["winerror", "errhandlingapi", "libloaderapi"]
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index bd1114b..1dfd507 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,13 +1,18 @@
 [package]
 name = "libloading"
-version = "0.6.2"
+# When bumping
+# * Don’t forget to add an entry to `src/changelog.rs`
+# * If bumping a incompatible version, adjust documentation in `src/lib.rs`
+version = "0.6.3"
 authors = ["Simonas Kazlauskas <libloading@kazlauskas.me>"]
-build = "build.rs"
-description = "A safer binding to platform’s dynamic library loading utilities"
-keywords = ["dlopen", "load", "shared", "dylib"]
 license = "ISC"
 repository = "https://github.com/nagisa/rust_libloading/"
 documentation = "https://docs.rs/libloading/"
+readme = "README.mkd"
+description = "A safer binding to platform’s dynamic library loading utilities"
+keywords = ["dlopen", "load", "shared", "dylib"]
+categories = ["api-bindings"]
+build = "build.rs"
 
 [target.'cfg(windows)'.dependencies.winapi]
 version = "0.3"
@@ -16,3 +21,14 @@
     "errhandlingapi",
     "libloaderapi",
 ]
+
+[target.'cfg(unix)'.dependencies.cfg-if]
+version = "0.1"
+
+[dev-dependencies]
+libc = "0.2"
+static_assertions = "1.1"
+
+[package.metadata.docs.rs]
+all-features = true
+rustdoc-args = ["--cfg", "docsrs"]
diff --git a/METADATA b/METADATA
index 01da0ad..f147aaf 100644
--- a/METADATA
+++ b/METADATA
@@ -9,11 +9,11 @@
     type: GIT
     value: "https://github.com/nagisa/rust_libloading"
   }
-  version: "0.6.2"
+  version: "0.6.3"
   license_type: NOTICE
   last_upgrade_date {
     year: 2020
-    month: 5
-    day: 5
+    month: 8
+    day: 24
   }
 }
diff --git a/README.mkd b/README.mkd
index 006f172..8f7d342 100644
--- a/README.mkd
+++ b/README.mkd
@@ -1,6 +1,6 @@
 # libloading
 
-A memory-safer wrapper around system dynamic library loading primitives. The most important safety
+Safer bindings around system dynamic library loading primitives. The most important safety
 guarantee by this library is prevention of dangling-`Symbol`s that may occur after a `Library` is
 unloaded.
 
@@ -13,4 +13,4 @@
 [docs]: https://docs.rs/libloading/
 [changelog]: https://docs.rs/libloading/*/libloading/changelog/index.html
 
-libloading is distributed under ISC (MIT-like) license.
+libloading is available to use under ISC (MIT-like) license.
diff --git a/build.rs b/build.rs
index fdc446d..e217f80 100644
--- a/build.rs
+++ b/build.rs
@@ -61,4 +61,10 @@
             ::std::process::exit(0xfd);
         }
     }
+
+    // For tests
+    println!(
+        "cargo:rustc-env=LIBLOADING_TEST_TARGET={}",
+        std::env::var("TARGET").expect("$TARGET is not set")
+    );
 }
diff --git a/src/changelog.rs b/src/changelog.rs
index 952eb5e..01c25ec 100644
--- a/src/changelog.rs
+++ b/src/changelog.rs
@@ -1,6 +1,18 @@
 //! Project changelog
 
 // TODO: for the next breaking release rename `Error::LoadLibraryW` to `Error::LoadLibraryExW`.
+// TODO: for the next breaking release use `RTLD_LAZY | RTLD_LOCAL` by default  on unix.
+
+/// Release 0.6.3 (2020-08-22)
+///
+/// * Improve documentation, allowing to view all of the os-specific functionality from
+/// documentation generated for any target;
+/// * Add [`os::windows::Library::this`];
+/// * Added constants to use with OS-specific `Library::open`;
+/// * Add [`library_filename`].
+///
+/// [`os::windows::Library::this`]: crate::os::windows::Library::this
+/// [`library_filename`]: crate::library_filename
 
 /// Release 0.6.2 (2020-05-06)
 ///
@@ -12,7 +24,7 @@
 /// * Introduced a new method [`os::windows::Library::load_with_flags`];
 /// * Added support for the Illumos triple.
 ///
-/// [`os::windows::Library::load_with_flags`]: ../../os/windows/struct.Library.html#method.load_with_flags
+/// [`os::windows::Library::load_with_flags`]: crate::os::windows::Library::load_with_flags
 pub mod r0_6_1 {}
 
 /// Release 0.6.0 (2020-04-05)
@@ -39,9 +51,9 @@
 ///   `dlsym` returns a null pointer. For the use-cases where loading null pointers is necessary
 ///   consider using [`os::unix::Library::get_singlethreaded`] instead.
 ///
-/// [`Library::get`]: ../../struct.Library.html#method.get
-/// [`os::unix::Library::get_singlethreaded`]: ../../os/unix/struct.Library.html#method.get_singlethreaded
-/// [`Error`]: ../../enum.Error.html
+/// [`Library::get`]: crate::Library::get
+/// [`os::unix::Library::get_singlethreaded`]: crate::os::unix::Library::get_singlethreaded
+/// [`Error`]: crate::Error
 pub mod r0_6_0 {}
 
 
diff --git a/src/error.rs b/src/error.rs
index dcbe2b1..6ba5367 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -1,5 +1,6 @@
 use std::ffi::CString;
 
+/// A `dlerror` error.
 pub struct DlDescription(pub(crate) CString);
 
 impl std::fmt::Debug for DlDescription {
@@ -8,6 +9,7 @@
     }
 }
 
+/// A Windows API error.
 pub struct WindowsError(pub(crate) std::io::Error);
 
 impl std::fmt::Debug for WindowsError {
@@ -16,39 +18,71 @@
     }
 }
 
+/// Errors.
 #[derive(Debug)]
 #[non_exhaustive]
 pub enum Error {
     /// The `dlopen` call failed.
-    DlOpen { desc: DlDescription },
+    DlOpen {
+        /// The source error.
+        desc: DlDescription
+    },
     /// The `dlopen` call failed and system did not report an error.
     DlOpenUnknown,
     /// The `dlsym` call failed.
-    DlSym { desc: DlDescription },
+    DlSym {
+        /// The source error.
+        desc: DlDescription
+    },
     /// The `dlsym` call failed and system did not report an error.
     DlSymUnknown,
     /// The `dlclose` call failed.
-    DlClose { desc: DlDescription },
+    DlClose {
+        /// The source error.
+        desc: DlDescription
+    },
     /// The `dlclose` call failed and system did not report an error.
     DlCloseUnknown,
     /// The `LoadLibraryW` call failed.
-    LoadLibraryW { source: WindowsError },
+    LoadLibraryW {
+        /// The source error.
+        source: WindowsError
+    },
     /// The `LoadLibraryW` call failed and system did not report an error.
     LoadLibraryWUnknown,
+    /// The `GetModuleHandleExW` call failed.
+    GetModuleHandleExW {
+        /// The source error.
+        source: WindowsError
+    },
+    /// The `LoadLibraryW` call failed and system did not report an error.
+    GetModuleHandleExWUnknown,
     /// The `GetProcAddress` call failed.
-    GetProcAddress { source: WindowsError },
+    GetProcAddress {
+        /// The source error.
+        source: WindowsError
+    },
     /// The `GetProcAddressUnknown` call failed and system did not report an error.
     GetProcAddressUnknown,
     /// The `FreeLibrary` call failed.
-    FreeLibrary { source: WindowsError },
+    FreeLibrary {
+        /// The source error.
+        source: WindowsError
+    },
     /// The `FreeLibrary` call failed and system did not report an error.
     FreeLibraryUnknown,
     /// The requested type cannot possibly work.
     IncompatibleSize,
     /// Could not create a new CString.
-    CreateCString { source: std::ffi::NulError },
+    CreateCString {
+        /// The source error.
+        source: std::ffi::NulError
+    },
     /// Could not create a new CString from bytes with trailing null.
-    CreateCStringWithTrailing { source: std::ffi::FromBytesWithNulError },
+    CreateCStringWithTrailing {
+        /// The source error.
+        source: std::ffi::FromBytesWithNulError
+    },
 }
 
 impl std::error::Error for Error {
@@ -75,9 +109,12 @@
             DlSymUnknown => write!(f, "dlsym failed, but system did not report the error"),
             DlClose { ref desc } => write!(f, "{}", desc.0.to_string_lossy()),
             DlCloseUnknown => write!(f, "dlclose failed, but system did not report the error"),
-            LoadLibraryW { .. } => write!(f, "LoadLibraryW failed"),
+            LoadLibraryW { .. } => write!(f, "LoadLibraryExW failed"),
             LoadLibraryWUnknown =>
-                write!(f, "LoadLibraryW failed, but system did not report the error"),
+                write!(f, "LoadLibraryExW failed, but system did not report the error"),
+            GetModuleHandleExW { .. } => write!(f, "GetModuleHandleExW failed"),
+            GetModuleHandleExWUnknown =>
+                write!(f, "GetModuleHandleExWUnknown failed, but system did not report the error"),
             GetProcAddress { .. } => write!(f, "GetProcAddress failed"),
             GetProcAddressUnknown =>
                 write!(f, "GetProcAddress failed, but system did not report the error"),
@@ -91,24 +128,3 @@
         }
     }
 }
-
-#[cfg(test)]
-mod tests {
-    #[test]
-    fn error_send() {
-        fn assert_send<T: Send>() {}
-        assert_send::<super::Error>();
-    }
-
-    #[test]
-    fn error_sync() {
-        fn assert_sync<T: Sync>() {}
-        assert_sync::<super::Error>();
-    }
-
-    #[test]
-    fn error_display() {
-        fn assert_display<T: std::fmt::Display>() {}
-        assert_display::<super::Error>();
-    }
-}
diff --git a/src/lib.rs b/src/lib.rs
index fad7d63..f6fc58d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -17,7 +17,7 @@
 //!
 //! ```toml
 //! [dependencies]
-//! libloading = "0.5"
+//! libloading = "0.6"
 //! ```
 //!
 //! Then inside your project
@@ -36,7 +36,17 @@
 //!
 //! The compiler will ensure that the loaded `function` will not outlive the `Library` it comes
 //! from, preventing a common cause of undefined behaviour and memory safety problems.
-use std::ffi::OsStr;
+#![deny(
+    missing_docs,
+    clippy::all,
+    unreachable_pub,
+    unused,
+)]
+#![cfg_attr(docsrs, deny(broken_intra_doc_links))]
+#![cfg_attr(docsrs, feature(doc_cfg))]
+
+use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
+use std::ffi::{OsStr, OsString};
 use std::fmt;
 use std::ops;
 use std::marker;
@@ -64,7 +74,7 @@
     /// * Absolute path to the library;
     /// * Relative (to the current working directory) path to the library.
     ///
-    /// ## Thread-safety
+    /// # Thread-safety
     ///
     /// The implementation strives to be as MT-safe as sanely possible, however due to certain
     /// error-handling related resources not always being safe, this library is not MT-safe either.
@@ -77,15 +87,17 @@
     /// [`SetErrorMode`]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms680621(v=vs.85).aspx
     ///
     /// Calling this function from multiple threads is not safe if used in conjunction with
-    /// path-less filename and library search path is modified (`SetDllDirectory` function on
+    /// relative filenames and the library search path is modified (`SetDllDirectory` function on
     /// Windows, `{DY,}LD_LIBRARY_PATH` environment variable on UNIX).
     ///
-    /// ## Platform-specific behaviour
+    /// # Platform-specific behaviour
     ///
     /// When a plain library filename is supplied, locations where library is searched for is
-    /// platform specific and cannot be adjusted in a portable manner.
+    /// platform specific and cannot be adjusted in a portable manner. See documentation for
+    /// the platform specific [`os::unix::Library::new`] and [`os::windows::Library::new`] methods
+    /// for further information on library lookup behaviour.
     ///
-    /// ### Windows
+    /// ## Windows
     ///
     /// If the `filename` specifies a library filename without path and with extension omitted,
     /// `.dll` extension is implicitly added. This behaviour may be suppressed by appending a
@@ -95,17 +107,18 @@
     /// `#[thread_local]` attributes), loading the library will fail on versions prior to Windows
     /// Vista.
     ///
-    /// ## Tips
+    /// # Tips
     ///
     /// Distributing your dynamic libraries under a filename common to all platforms (e.g.
     /// `awesome.module`) allows to avoid code which has to account for platform’s conventional
     /// library filenames.
     ///
-    /// Strive to specify absolute or relative path to your library, unless system-wide libraries
-    /// are being loaded.  Platform-dependent library search locations combined with various quirks
-    /// related to path-less filenames may cause flaky code.
+    /// Strive to specify an absolute or at least a relative path to your library, unless
+    /// system-wide libraries are being loaded. Platform-dependent library search locations
+    /// combined with various quirks related to path-less filenames may cause flakiness in
+    /// programs.
     ///
-    /// ## Examples
+    /// # Examples
     ///
     /// ```no_run
     /// # use ::libloading::Library;
@@ -126,16 +139,16 @@
     /// Symbol is interpreted as-is; no mangling is done. This means that symbols like `x::y` are
     /// most likely invalid.
     ///
-    /// ## Unsafety
+    /// # Safety
     ///
     /// Pointer to a value of arbitrary type is returned. Using a value with wrong type is
     /// undefined.
     ///
-    /// ## Platform-specific behaviour
+    /// # Platform-specific behaviour
     ///
-    /// On Linux and Windows, a TLS variable acts just like any regular global variable. OS X uses
-    /// some sort of lazy initialization scheme, which makes loading TLS variables this way
-    /// impossible. Using a TLS variable loaded this way on OS X is undefined behaviour.
+    /// Implementation of thread local variables is extremely platform specific and uses of these
+    /// variables that work on e.g. Linux may have unintended behaviour on other POSIX systems or
+    /// Windows.
     ///
     /// On POSIX implementations where the `dlerror` function is not confirmed to be MT-safe (such
     /// as FreeBSD), this function will unconditionally return an error the underlying `dlsym` call
@@ -143,7 +156,7 @@
     /// pointer without it being an error. If loading a null pointer is something you care about,
     /// consider using the [`os::unix::Library::get_singlethreaded`] call.
     ///
-    /// ## Examples
+    /// # Examples
     ///
     /// Given a loaded library:
     ///
@@ -232,12 +245,13 @@
 impl<'lib, T> Symbol<'lib, T> {
     /// Extract the wrapped `os::platform::Symbol`.
     ///
-    /// ## Unsafety
+    /// # Safety
+    ///
     /// Using this function relinquishes all the lifetime guarantees. It is up to programmer to
     /// ensure the resulting `Symbol` is not used past the lifetime of the `Library` this symbol
     /// was loaded from.
     ///
-    /// ## Examples
+    /// # Examples
     ///
     /// ```no_run
     /// # use ::libloading::{Library, Symbol};
@@ -256,12 +270,12 @@
     /// Note that, in order to create association between the symbol and the library this symbol
     /// came from, this function requires reference to the library provided.
     ///
-    /// ## Unsafety
+    /// # Safety
     ///
     /// It is invalid to provide a reference to any other value other than the library the `sym`
     /// was loaded from. Doing so invalidates any lifetime guarantees.
     ///
-    /// ## Examples
+    /// # Examples
     ///
     /// ```no_run
     /// # use ::libloading::{Library, Symbol};
@@ -283,7 +297,7 @@
 impl<'lib, T> Symbol<'lib, Option<T>> {
     /// Lift Option out of the symbol.
     ///
-    /// ## Examples
+    /// # Examples
     ///
     /// ```no_run
     /// # use ::libloading::{Library, Symbol};
@@ -326,3 +340,27 @@
 
 unsafe impl<'lib, T: Send> Send for Symbol<'lib, T> {}
 unsafe impl<'lib, T: Sync> Sync for Symbol<'lib, T> {}
+
+/// Converts a library name to a filename generally appropriate for use on the system.
+///
+/// The function will prepend prefixes (such as `lib`) and suffixes (such as `.so`) to the library
+/// `name` to construct the filename.
+///
+/// # Examples
+///
+/// It can be used to load global libraries in a platform independent manner:
+///
+/// ```
+/// use libloading::{Library, library_filename};
+/// // Will attempt to load `libLLVM.so` on Linux, `libLLVM.dylib` on macOS and `LLVM.dll` on
+/// // Windows.
+/// let library = Library::new(library_filename("LLVM"));
+/// ```
+pub fn library_filename<S: AsRef<OsStr>>(name: S) -> OsString {
+    let name = name.as_ref();
+    let mut string = OsString::with_capacity(name.len() + DLL_PREFIX.len() + DLL_SUFFIX.len());
+    string.push(DLL_PREFIX);
+    string.push(name);
+    string.push(DLL_SUFFIX);
+    string
+}
diff --git a/src/os/mod.rs b/src/os/mod.rs
index ccbc8e9..40361c5 100644
--- a/src/os/mod.rs
+++ b/src/os/mod.rs
@@ -16,30 +16,12 @@
 //! use libloading::os::windows::*;
 //! ```
 
-macro_rules! unix {
-    ($item: item) => {
-        /// UNIX implementation of dynamic library loading.
-        ///
-        /// This module should be expanded with more UNIX-specific functionality in the future.
-        $item
-    }
-}
+/// UNIX implementation of dynamic library loading.
+#[cfg(any(unix, docsrs))]
+#[cfg_attr(docsrs, doc(cfg(unix)))]
+pub mod unix;
 
-macro_rules! windows {
-    ($item: item) => {
-        /// Windows implementation of dynamic library loading.
-        ///
-        /// This module should be expanded with more Windows-specific functionality in the future.
-        $item
-    }
-}
-
-#[cfg(unix)]
-unix!(pub mod unix;);
-#[cfg(unix)]
-windows!(pub mod windows {});
-
-#[cfg(windows)]
-windows!(pub mod windows;);
-#[cfg(windows)]
-unix!(pub mod unix {});
+/// Windows implementation of dynamic library loading.
+#[cfg(any(windows, docsrs))]
+#[cfg_attr(docsrs, doc(cfg(windows)))]
+pub mod windows;
diff --git a/src/os/unix/consts.rs b/src/os/unix/consts.rs
new file mode 100644
index 0000000..823155e
--- /dev/null
+++ b/src/os/unix/consts.rs
@@ -0,0 +1,230 @@
+use std::os::raw::c_int;
+
+/// Perform lazy binding.
+///
+/// Relocations shall be performed at an implementation-defined time, ranging from the time
+/// of the [`Library::open`] call until the first reference to a given symbol occurs.
+/// Specifying `RTLD_LAZY` should improve performance on implementations supporting dynamic
+/// symbol binding since a process might not reference all of the symbols in an executable
+/// object file. And, for systems supporting dynamic symbol resolution for normal process
+/// execution, this behavior mimics the normal handling of process execution.
+///
+/// Conflicts with [`RTLD_NOW`].
+///
+/// [`Library::open`]: crate::os::unix::Library::open
+pub const RTLD_LAZY: c_int = posix::RTLD_LAZY;
+
+/// Perform eager binding.
+///
+/// All necessary relocations shall be performed when the executable object file is first
+/// loaded. This may waste some processing if relocations are performed for symbols
+/// that are never referenced. This behavior may be useful for applications that need to
+/// know that all symbols referenced during execution will be available before
+/// [`Library::open`] returns.
+///
+/// Conflicts with [`RTLD_LAZY`].
+///
+/// [`Library::open`]: crate::os::unix::Library::open
+pub const RTLD_NOW: c_int = posix::RTLD_NOW;
+
+/// Make loaded symbols available for resolution globally.
+///
+/// The executable object file's symbols shall be made available for relocation processing of any
+/// other executable object file. In addition, calls to [`Library::get`] on `Library` obtained from
+/// [`Library::this`] allows executable object files loaded with this mode to be searched.
+///
+/// [`Library::this`]: crate::os::unix::Library::this
+/// [`Library::get`]: crate::os::unix::Library::get
+pub const RTLD_GLOBAL: c_int = posix::RTLD_GLOBAL;
+
+/// Load symbols into an isolated namespace.
+///
+/// The executable object file's symbols shall not be made available for relocation processing of
+/// any other executable object file. This mode of operation is most appropriate for e.g. plugins.
+pub const RTLD_LOCAL: c_int = posix::RTLD_LOCAL;
+
+#[cfg(docsrs)]
+mod posix {
+    use super::c_int;
+    pub(super) const RTLD_LAZY: c_int = !0;
+    pub(super) const RTLD_NOW: c_int = !0;
+    pub(super) const RTLD_GLOBAL: c_int = !0;
+    pub(super) const RTLD_LOCAL: c_int = !0;
+}
+
+#[cfg(not(docsrs))]
+mod posix {
+    extern crate cfg_if;
+    use self::cfg_if::cfg_if;
+    use super::c_int;
+    cfg_if! {
+        if #[cfg(target_os = "haiku")] {
+            pub(super) const RTLD_LAZY: c_int = 0;
+        } else if #[cfg(any(
+            target_os = "linux",
+            target_os = "android",
+            target_os = "emscripten",
+
+            target_os = "macos",
+            target_os = "ios",
+            target_os = "freebsd",
+            target_os = "dragonfly",
+            target_os = "openbsd",
+            target_os = "netbsd",
+
+            target_os = "solaris",
+            target_os = "illumos",
+
+            target_env = "uclibc",
+            target_env = "newlib",
+
+            target_os = "fuchsia",
+            target_os = "redox",
+        ))] {
+            pub(super) const RTLD_LAZY: c_int = 1;
+        } else {
+            compile_error!(
+                "Target has no known `RTLD_LAZY` value. Please submit an issue or PR adding it."
+            );
+        }
+    }
+
+    cfg_if! {
+        if #[cfg(target_os = "haiku")] {
+            pub(super) const RTLD_NOW: c_int = 1;
+        } else if #[cfg(any(
+            target_os = "linux",
+            all(target_os = "android", target_pointer_width = "64"),
+            target_os = "emscripten",
+
+            target_os = "macos",
+            target_os = "ios",
+            target_os = "freebsd",
+            target_os = "dragonfly",
+            target_os = "openbsd",
+            target_os = "netbsd",
+
+            target_os = "solaris",
+            target_os = "illumos",
+
+            target_env = "uclibc",
+            target_env = "newlib",
+
+            target_os = "fuchsia",
+            target_os = "redox",
+        ))] {
+            pub(super) const RTLD_NOW: c_int = 2;
+        } else if #[cfg(all(target_os = "android",target_pointer_width = "32"))] {
+            pub(super) const RTLD_NOW: c_int = 0;
+        } else {
+            compile_error!(
+                "Target has no known `RTLD_NOW` value. Please submit an issue or PR adding it."
+            );
+        }
+    }
+
+    cfg_if! {
+        if #[cfg(any(
+            target_os = "haiku",
+            all(target_os = "android",target_pointer_width = "32"),
+        ))] {
+            pub(super) const RTLD_GLOBAL: c_int = 2;
+        } else if #[cfg(any(
+            target_env = "uclibc",
+            all(target_os = "linux", target_arch = "mips"),
+            all(target_os = "linux", target_arch = "mips64"),
+        ))] {
+            pub(super) const RTLD_GLOBAL: c_int = 4;
+        } else if #[cfg(any(
+            target_os = "macos",
+            target_os = "ios",
+        ))] {
+            pub(super) const RTLD_GLOBAL: c_int = 8;
+        } else if #[cfg(any(
+            target_os = "linux",
+            all(target_os = "android", target_pointer_width = "64"),
+            target_os = "emscripten",
+
+            target_os = "freebsd",
+            target_os = "dragonfly",
+            target_os = "openbsd",
+            target_os = "netbsd",
+
+            target_os = "solaris",
+            target_os = "illumos",
+
+            target_env = "newlib",
+
+            target_os = "fuchsia",
+            target_os = "redox",
+        ))] {
+            pub(super) const RTLD_GLOBAL: c_int = 0x100;
+        } else {
+            compile_error!(
+                "Target has no known `RTLD_GLOBAL` value. Please submit an issue or PR adding it."
+            );
+        }
+    }
+
+    cfg_if! {
+        if #[cfg(target_os = "netbsd")] {
+            pub(super) const RTLD_LOCAL: c_int = 0x200;
+        } else if #[cfg(any(
+            target_os = "macos",
+            target_os = "ios",
+        ))] {
+            pub(super) const RTLD_LOCAL: c_int = 4;
+        } else if #[cfg(any(
+            target_os = "linux",
+            target_os = "android",
+            target_os = "emscripten",
+
+            target_os = "freebsd",
+            target_os = "dragonfly",
+            target_os = "openbsd",
+
+            target_os = "haiku",
+
+            target_os = "solaris",
+            target_os = "illumos",
+
+            target_env = "uclibc",
+            target_env = "newlib",
+
+            target_os = "fuchsia",
+            target_os = "redox",
+        ))] {
+            pub(super) const RTLD_LOCAL: c_int = 0;
+        } else {
+            compile_error!(
+                "Target has no known `RTLD_LOCAL` value. Please submit an issue or PR adding it."
+            );
+        }
+    }
+}
+
+// Other constants that exist but are not bound because they are platform-specific (non-posix)
+// extensions. Some of these constants are only relevant to `dlsym` or `dlmopen` calls.
+//
+// RTLD_CONFGEN
+// RTLD_DEFAULT
+// RTLD_DI_CONFIGADDR
+// RTLD_DI_LINKMAP
+// RTLD_DI_LMID
+// RTLD_DI_ORIGIN
+// RTLD_DI_PROFILENAME
+// RTLD_DI_PROFILEOUT
+// RTLD_DI_SERINFO
+// RTLD_DI_SERINFOSIZE
+// RTLD_DI_TLS_DATA
+// RTLD_DI_TLS_MODID
+// RTLD_FIRST
+// RTLD_GROUP
+// RTLD_NEXT
+// RTLD_PARENT
+// RTLD_PROBE
+// RTLD_SELF
+// RTLD_WORLD
+// RTLD_NODELETE
+// RTLD_NOLOAD
+// RTLD_DEEPBIND
diff --git a/src/os/unix/mod.rs b/src/os/unix/mod.rs
index 29d2003..785c58f 100644
--- a/src/os/unix/mod.rs
+++ b/src/os/unix/mod.rs
@@ -1,9 +1,21 @@
-use util::{ensure_compatible_types, cstr_cow_from_bytes};
+// A hack for docs.rs to build documentation that has both windows and linux documentation in the
+// same rustdoc build visible.
+#[cfg(all(docsrs, not(unix)))]
+mod unix_imports {
+}
+#[cfg(any(not(docsrs), unix))]
+mod unix_imports {
+    pub(super) use std::os::unix::ffi::OsStrExt;
+}
 
+use self::unix_imports::*;
+use util::{ensure_compatible_types, cstr_cow_from_bytes};
 use std::ffi::{CStr, OsStr};
 use std::{fmt, marker, mem, ptr};
 use std::os::raw;
-use std::os::unix::ffi::OsStrExt;
+pub use self::consts::*;
+
+mod consts;
 
 // dl* family of functions did not have enough thought put into it.
 //
@@ -61,7 +73,7 @@
     })
 }
 
-/// A platform-specific equivalent of the cross-platform `Library`.
+/// A platform-specific counterpart of the cross-platform [`Library`](crate::Library).
 pub struct Library {
     handle: *mut raw::c_void
 }
@@ -85,34 +97,45 @@
 unsafe impl Sync for Library {}
 
 impl Library {
-    /// Find and load a shared library (module).
+    /// Find and eagerly load a shared library (module).
     ///
-    /// Locations where library is searched for is platform specific and can’t be adjusted
-    /// portably.
+    /// If the `filename` contains a [path separator], the `filename` is interpreted as a `path` to
+    /// a file. Otherwise, platform-specific algorithms are employed to find a library with a
+    /// matching file name.
     ///
-    /// Corresponds to `dlopen(filename, RTLD_NOW)`.
+    /// This is equivalent to [`Library::open`]`(filename, RTLD_NOW)`.
+    ///
+    /// [path separator]: std::path::MAIN_SEPARATOR
     #[inline]
     pub fn new<P: AsRef<OsStr>>(filename: P) -> Result<Library, crate::Error> {
         Library::open(Some(filename), RTLD_NOW)
     }
 
-    /// Load the dynamic libraries linked into main program.
+    /// Eagerly load the `Library` representing the current executable.
     ///
-    /// This allows retrieving symbols from any **dynamic** library linked into the program,
-    /// without specifying the exact library.
+    /// [`Library::get`] calls of the returned `Library` will look for symbols in following
+    /// locations in order:
     ///
-    /// Corresponds to `dlopen(NULL, RTLD_NOW)`.
+    /// 1. Original program image;
+    /// 2. Any executable object files (e.g. shared libraries) loaded at program startup;
+    /// 3. Executable object files loaded at runtime (e.g. via other `Library::new` calls or via
+    ///    calls to the `dlopen` function)
+    ///
+    /// Note that behaviour of `Library` loaded with this method is different from
+    /// Libraries loaded with [`os::windows::Library::this`].
+    ///
+    /// This is equivalent to [`Library::open`]`(None, RTLD_NOW)`.
+    ///
+    /// [`os::windows::Library::this`]: crate::os::windows::Library::this
     #[inline]
     pub fn this() -> Library {
         Library::open(None::<&OsStr>, RTLD_NOW).expect("this should never fail")
     }
 
-    /// Find and load a shared library (module).
+    /// Find and load an executable object file (shared library).
     ///
-    /// Locations where library is searched for is platform specific and can’t be adjusted
-    /// portably.
-    ///
-    /// If the `filename` is None, null pointer is passed to `dlopen`.
+    /// See documentation for [`Library::this`] for further description of behaviour
+    /// when the `filename` is `None`. Otherwise see [`Library::new`].
     ///
     /// Corresponds to `dlopen(filename, flags)`.
     pub fn open<P>(filename: Option<P>, flags: raw::c_int) -> Result<Library, crate::Error>
@@ -174,37 +197,33 @@
     /// Get a pointer to function or static variable by symbol name.
     ///
     /// The `symbol` may not contain any null bytes, with an exception of last byte. A null
-    /// terminated `symbol` may avoid a string allocation in some cases.
+    /// terminated `symbol` may avoid an allocation in some cases.
     ///
     /// Symbol is interpreted as-is; no mangling is done. This means that symbols like `x::y` are
     /// most likely invalid.
     ///
-    /// ## Unsafety
+    /// # Safety
     ///
     /// This function does not validate the type `T`. It is up to the user of this function to
     /// ensure that the loaded symbol is in fact a `T`. Using a value with a wrong type has no
-    /// definied behaviour.
+    /// defined behaviour.
     ///
+    /// # Platform-specific behaviour
     ///
-    ///
-    /// ## Platform-specific behaviour
-    ///
-    /// OS X uses some sort of lazy initialization scheme, which makes loading TLS variables
-    /// impossible. Using a TLS variable loaded this way on OS X is undefined behaviour.
+    /// Implementation of thread local variables is extremely platform specific and uses of these
+    /// variables that work on e.g. Linux may have unintended behaviour on other POSIX systems.
     ///
     /// On POSIX implementations where the `dlerror` function is not confirmed to be MT-safe (such
-    /// as FreeBSD), this function will unconditionally return an error the underlying `dlsym` call
-    /// returns a null pointer. There are rare situations where `dlsym` returns a genuine null
-    /// pointer without it being an error. If loading a null pointer is something you care about,
-    /// consider using the [`Library::get_singlethreaded`] call.
+    /// as FreeBSD), this function will unconditionally return an error when the underlying `dlsym`
+    /// call returns a null pointer. There are rare situations where `dlsym` returns a genuine null
+    /// pointer without it being an error. If loading a symbol at null address is something you
+    /// care about, consider using the [`Library::get_singlethreaded`] call.
     #[inline(always)]
     pub unsafe fn get<T>(&self, symbol: &[u8]) -> Result<Symbol<T>, crate::Error> {
         #[cfg(mtsafe_dlerror)]
-        { return self.get_singlethreaded(symbol); }
+        { self.get_singlethreaded(symbol) }
         #[cfg(not(mtsafe_dlerror))]
-        {
-            return self.get_impl(symbol, || Err(crate::Error::DlSymUnknown));
-        }
+        { self.get_impl(symbol, || Err(crate::Error::DlSymUnknown)) }
     }
 
     /// Get a pointer to function or static variable by symbol name.
@@ -215,20 +234,20 @@
     /// Symbol is interpreted as-is; no mangling is done. This means that symbols like `x::y` are
     /// most likely invalid.
     ///
-    /// ## Unsafety
+    /// # Safety
     ///
     /// This function does not validate the type `T`. It is up to the user of this function to
     /// ensure that the loaded symbol is in fact a `T`. Using a value with a wrong type has no
-    /// definied behaviour.
+    /// defined behaviour.
     ///
     /// It is up to the user of this library to ensure that no other calls to an MT-unsafe
-    /// implementation of `dlerror` occur while this function is executing. Failing that the
-    /// results of this function are not defined.
+    /// implementation of `dlerror` occur during execution of this function. Failing that, the
+    /// behaviour of this function is not defined.
     ///
-    /// ## Platform-specific behaviour
+    /// # Platform-specific behaviour
     ///
-    /// OS X uses some sort of lazy initialization scheme, which makes loading TLS variables
-    /// impossible. Using a TLS variable loaded this way on OS X is undefined behaviour.
+    /// Implementation of thread local variables is extremely platform specific and uses of these
+    /// variables that work on e.g. Linux may have unintended behaviour on other POSIX systems.
     #[inline(always)]
     pub unsafe fn get_singlethreaded<T>(&self, symbol: &[u8]) -> Result<Symbol<T>, crate::Error> {
         self.get_impl(symbol, || Ok(Symbol {
@@ -249,14 +268,14 @@
 
     /// Convert a raw handle returned by `dlopen`-family of calls to a `Library`.
     ///
-    /// ## Unsafety
+    /// # Safety
     ///
     /// The pointer shall be a result of a successful call of the `dlopen`-family of functions or a
     /// pointer previously returned by `Library::into_raw` call. It must be valid to call `dlclose`
     /// with this pointer as an argument.
     pub unsafe fn from_raw(handle: *mut raw::c_void) -> Library {
         Library {
-            handle: handle
+            handle
         }
     }
 
@@ -266,8 +285,7 @@
     /// what library was opened or other platform specifics.
     ///
     /// You only need to call this if you are interested in handling any errors that may arise when
-    /// library is unloaded. Otherwise the implementation of `Drop` for `Library` will close the
-    /// library and ignore the errors were they arise.
+    /// library is unloaded. Otherwise this will be done when `Library` is dropped.
     pub fn close(self) -> Result<(), crate::Error> {
         let result = with_dlerror(|desc| crate::Error::DlClose { desc }, || {
             if unsafe { dlclose(self.handle) } == 0 {
@@ -341,7 +359,7 @@
     fn deref(&self) -> &T {
         unsafe {
             // Additional reference level for a dereference on `deref` return value.
-            mem::transmute(&self.pointer)
+            &*(&self.pointer as *const *mut _ as *const T)
         }
     }
 }
@@ -369,7 +387,6 @@
 }
 
 // Platform specific things
-
 extern {
     fn dlopen(filename: *const raw::c_char, flags: raw::c_int) -> *mut raw::c_void;
     fn dlclose(handle: *mut raw::c_void) -> raw::c_int;
@@ -378,11 +395,6 @@
     fn dladdr(addr: *mut raw::c_void, info: *mut DlInfo) -> raw::c_int;
 }
 
-#[cfg(not(target_os="android"))]
-const RTLD_NOW: raw::c_int = 2;
-#[cfg(target_os="android")]
-const RTLD_NOW: raw::c_int = 0;
-
 #[repr(C)]
 struct DlInfo {
   dli_fname: *const raw::c_char,
@@ -390,11 +402,3 @@
   dli_sname: *const raw::c_char,
   dli_saddr: *mut raw::c_void
 }
-
-#[cfg(test)]
-mod tests {
-    #[test]
-    fn this() {
-        super::Library::this();
-    }
-}
diff --git a/src/os/windows/mod.rs b/src/os/windows/mod.rs
index 3620b3e..a106234 100644
--- a/src/os/windows/mod.rs
+++ b/src/os/windows/mod.rs
@@ -1,17 +1,63 @@
-extern crate winapi;
-use self::winapi::shared::minwindef::{WORD, DWORD, HMODULE, FARPROC};
-use self::winapi::shared::ntdef::WCHAR;
-use self::winapi::shared::winerror;
-use self::winapi::um::{errhandlingapi, libloaderapi};
+// A hack for docs.rs to build documentation that has both windows and linux documentation in the
+// same rustdoc build visible.
+#[cfg(all(docsrs, not(windows)))]
+mod windows_imports {
+    pub(super) enum WORD {}
+    pub(super) struct DWORD;
+    pub(super) enum HMODULE {}
+    pub(super) enum FARPROC {}
 
+    pub(super) mod consts {
+        use super::DWORD;
+        pub(crate) const LOAD_IGNORE_CODE_AUTHZ_LEVEL: DWORD = DWORD;
+        pub(crate) const LOAD_LIBRARY_AS_DATAFILE: DWORD = DWORD;
+        pub(crate) const LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE: DWORD = DWORD;
+        pub(crate) const LOAD_LIBRARY_AS_IMAGE_RESOURCE: DWORD = DWORD;
+        pub(crate) const LOAD_LIBRARY_SEARCH_APPLICATION_DIR: DWORD = DWORD;
+        pub(crate) const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: DWORD = DWORD;
+        pub(crate) const LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR: DWORD = DWORD;
+        pub(crate) const LOAD_LIBRARY_SEARCH_SYSTEM32: DWORD = DWORD;
+        pub(crate) const LOAD_LIBRARY_SEARCH_USER_DIRS: DWORD = DWORD;
+        pub(crate) const LOAD_WITH_ALTERED_SEARCH_PATH: DWORD = DWORD;
+        pub(crate) const LOAD_LIBRARY_REQUIRE_SIGNED_TARGET: DWORD = DWORD;
+        pub(crate) const LOAD_LIBRARY_SAFE_CURRENT_DIRS: DWORD = DWORD;
+    }
+}
+#[cfg(any(not(docsrs), windows))]
+mod windows_imports {
+    extern crate winapi;
+    pub(super) use self::winapi::shared::minwindef::{WORD, DWORD, HMODULE, FARPROC};
+    pub(super) use self::winapi::shared::ntdef::WCHAR;
+    pub(super) use self::winapi::shared::winerror;
+    pub(super) use self::winapi::um::{errhandlingapi, libloaderapi};
+    pub(super) use std::os::windows::ffi::{OsStrExt, OsStringExt};
+    pub(super) const SEM_FAILCE: DWORD = 1;
+
+    pub(super) mod consts {
+        pub(crate) use super::winapi::um::libloaderapi::{
+            LOAD_IGNORE_CODE_AUTHZ_LEVEL,
+            LOAD_LIBRARY_AS_DATAFILE,
+            LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE,
+            LOAD_LIBRARY_AS_IMAGE_RESOURCE,
+            LOAD_LIBRARY_SEARCH_APPLICATION_DIR,
+            LOAD_LIBRARY_SEARCH_DEFAULT_DIRS,
+            LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR,
+            LOAD_LIBRARY_SEARCH_SYSTEM32,
+            LOAD_LIBRARY_SEARCH_USER_DIRS,
+            LOAD_WITH_ALTERED_SEARCH_PATH,
+            LOAD_LIBRARY_REQUIRE_SIGNED_TARGET,
+            LOAD_LIBRARY_SAFE_CURRENT_DIRS,
+        };
+    }
+}
+
+use self::windows_imports::*;
 use util::{ensure_compatible_types, cstr_cow_from_bytes};
-
 use std::ffi::{OsStr, OsString};
 use std::{fmt, io, marker, mem, ptr};
-use std::os::windows::ffi::{OsStrExt, OsStringExt};
 use std::sync::atomic::{AtomicBool, Ordering};
 
-/// A platform-specific equivalent of the cross-platform `Library`.
+/// A platform-specific counterpart of the cross-platform [`Library`](crate::Library).
 pub struct Library(HMODULE);
 
 unsafe impl Send for Library {}
@@ -31,20 +77,56 @@
 unsafe impl Sync for Library {}
 
 impl Library {
-    /// Find and load a shared library (module).
+    /// Find and load a module.
     ///
-    /// Corresponds to `LoadLibraryW(filename, reserved: NULL, flags: 0)` which is equivalent to `LoadLibraryW(filename)`
+    /// If the `filename` specifies a full path, the function only searches that path for the
+    /// module. Otherwise, if the `filename` specifies a relative path or a module name without a
+    /// path, the function uses a windows-specific search strategy to find the module; for more
+    /// information, see the [Remarks on MSDN][msdn].
+    ///
+    /// If the `filename` specifies a library filename without path and with extension omitted,
+    /// `.dll` extension is implicitly added. This behaviour may be suppressed by appending a
+    /// trailing `.` to the `filename`.
+    ///
+    /// This is equivalent to [`Library::load_with_flags`]`(filename, 0)`.
+    ///
+    /// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryw#remarks
     #[inline]
     pub fn new<P: AsRef<OsStr>>(filename: P) -> Result<Library, crate::Error> {
         Library::load_with_flags(filename, 0)
     }
 
-    /// Find and load a shared library (module).
+    /// Load the `Library` representing the original program executable.
     ///
-    /// Locations where library is searched for is platform specific and can’t be adjusted
-    /// portably.
+    /// Note that behaviour of `Library` loaded with this method is different from
+    /// Libraries loaded with [`os::unix::Library::this`]. For more information refer to [MSDN].
     ///
-    /// Corresponds to `LoadLibraryW(filename, reserved: NULL, flags)`.
+    /// Corresponds to `GetModuleHandleExW(0, NULL, _)`.
+    ///
+    /// [`os::unix::Library::this`]: crate::os::unix::Library::this
+    /// [MSDN]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulehandleexw
+    pub fn this() -> Result<Library, crate::Error> {
+        unsafe {
+            let mut handle: HMODULE = std::ptr::null_mut();
+            with_get_last_error(|source| crate::Error::GetModuleHandleExW { source }, || {
+                let result = libloaderapi::GetModuleHandleExW(0, std::ptr::null_mut(), &mut handle);
+                if result == 0 {
+                    None
+                } else {
+                    Some(Library(handle))
+                }
+            }).map_err(|e| e.unwrap_or(crate::Error::GetModuleHandleExWUnknown))
+        }
+    }
+
+    /// Find and load a module, additionally adjusting behaviour with flags.
+    ///
+    /// See [`Library::new`] for documentation on handling of the `filename` argument. See the
+    /// [flag table on MSDN][flags] for information on applicable values for the `flags` argument.
+    ///
+    /// Corresponds to `LoadLibraryExW(filename, reserved: NULL, flags)`.
+    ///
+    /// [flags]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters
     pub fn load_with_flags<P: AsRef<OsStr>>(filename: P, flags: DWORD) -> Result<Library, crate::Error> {
         let wide_filename: Vec<u16> = filename.as_ref().encode_wide().chain(Some(0)).collect();
         let _guard = ErrorModeGuard::new();
@@ -52,7 +134,9 @@
         let ret = with_get_last_error(|source| crate::Error::LoadLibraryW { source }, || {
             // Make sure no winapi calls as a result of drop happen inside this closure, because
             // otherwise that might change the return value of the GetLastError.
-            let handle = unsafe { libloaderapi::LoadLibraryExW(wide_filename.as_ptr(), std::ptr::null_mut(), flags) };
+            let handle = unsafe {
+                libloaderapi::LoadLibraryExW(wide_filename.as_ptr(), std::ptr::null_mut(), flags)
+            };
             if handle.is_null()  {
                 None
             } else {
@@ -72,7 +156,7 @@
     /// Symbol is interpreted as-is; no mangling is done. This means that symbols like `x::y` are
     /// most likely invalid.
     ///
-    /// ## Unsafety
+    /// # Safety
     ///
     /// This function does not validate the type `T`. It is up to the user of this function to
     /// ensure that the loaded symbol is in fact a `T`. Using a value with a wrong type has no
@@ -95,7 +179,7 @@
 
     /// Get a pointer to function or static variable by ordinal number.
     ///
-    /// ## Unsafety
+    /// # Safety
     ///
     /// Pointer to a value of arbitrary type is returned. Using a value with wrong type is
     /// undefined.
@@ -124,7 +208,7 @@
 
     /// Convert a raw handle to a `Library`.
     ///
-    /// ## Unsafety
+    /// # Safety
     ///
     /// The handle shall be a result of a successful call of `LoadLibraryW` or a
     /// handle previously returned by the `Library::into_raw` call.
@@ -217,7 +301,7 @@
     fn deref(&self) -> &T {
         unsafe {
             // Additional reference level for a dereference on `deref` return value.
-            mem::transmute(&self.pointer)
+            &*(&self.pointer as *const *mut _ as *const T)
         }
     }
 }
@@ -228,13 +312,12 @@
     }
 }
 
-
 static USE_ERRORMODE: AtomicBool = AtomicBool::new(false);
 struct ErrorModeGuard(DWORD);
 
 impl ErrorModeGuard {
+    #[allow(clippy::if_same_then_else)]
     fn new() -> Option<ErrorModeGuard> {
-        const SEM_FAILCE: DWORD = 1;
         unsafe {
             if !USE_ERRORMODE.load(Ordering::Acquire) {
                 let mut previous_mode = 0;
@@ -302,31 +385,114 @@
     })
 }
 
-#[cfg(test)]
-mod tests {
-    use super::*;
+/// Do not check AppLocker rules or apply Software Restriction Policies for the DLL.
+///
+/// This action applies only to the DLL being loaded and not to its dependencies. This value is
+/// recommended for use in setup programs that must run extracted DLLs during installation.
+///
+/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
+pub const LOAD_IGNORE_CODE_AUTHZ_LEVEL: DWORD = consts::LOAD_IGNORE_CODE_AUTHZ_LEVEL;
 
-    #[test]
-    fn works_getlasterror() {
-        let lib = Library::new("kernel32.dll").unwrap();
-        let gle: Symbol<unsafe extern "system" fn() -> DWORD> = unsafe {
-            lib.get(b"GetLastError").unwrap()
-        };
-        unsafe {
-            errhandlingapi::SetLastError(42);
-            assert_eq!(errhandlingapi::GetLastError(), gle())
-        }
-    }
+/// Map the file into the calling process’ virtual address space as if it were a data file.
+///
+/// Nothing is done to execute or prepare to execute the mapped file. Therefore, you cannot call
+/// functions like [`Library::get`] with this DLL. Using this value causes writes to read-only
+/// memory to raise an access violation. Use this flag when you want to load a DLL only to extract
+/// messages or resources from it.
+///
+/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
+pub const LOAD_LIBRARY_AS_DATAFILE: DWORD = consts::LOAD_LIBRARY_AS_DATAFILE;
 
-    #[test]
-    fn works_getlasterror0() {
-        let lib = Library::new("kernel32.dll").unwrap();
-        let gle: Symbol<unsafe extern "system" fn() -> DWORD> = unsafe {
-            lib.get(b"GetLastError\0").unwrap()
-        };
-        unsafe {
-            errhandlingapi::SetLastError(42);
-            assert_eq!(errhandlingapi::GetLastError(), gle())
-        }
-    }
-}
+/// Map the file into the calling process’ virtual address space as if it were a data file.
+///
+/// Similar to [`LOAD_LIBRARY_AS_DATAFILE`], except that the DLL file is opened with exclusive
+/// write access for the calling process. Other processes cannot open the DLL file for write access
+/// while it is in use. However, the DLL can still be opened by other processes.
+///
+/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
+pub const LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE: DWORD = consts::LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE;
+
+/// Map the file into the process’ virtual address space as an image file.
+///
+/// The loader does not load the static imports or perform the other usual initialization steps.
+/// Use this flag when you want to load a DLL only to extract messages or resources from it.
+///
+/// Unless the application depends on the file having the in-memory layout of an image, this value
+/// should be used with either [`LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE`] or
+/// [`LOAD_LIBRARY_AS_DATAFILE`].
+///
+/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
+pub const LOAD_LIBRARY_AS_IMAGE_RESOURCE: DWORD = consts::LOAD_LIBRARY_AS_IMAGE_RESOURCE;
+
+/// Search application's installation directory for the DLL and its dependencies.
+///
+/// Directories in the standard search path are not searched. This value cannot be combined with
+/// [`LOAD_WITH_ALTERED_SEARCH_PATH`].
+///
+/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
+pub const LOAD_LIBRARY_SEARCH_APPLICATION_DIR: DWORD = consts::LOAD_LIBRARY_SEARCH_APPLICATION_DIR;
+
+/// Search default directories when looking for the DLL and its dependencies.
+///
+/// This value is a combination of [`LOAD_LIBRARY_SEARCH_APPLICATION_DIR`],
+/// [`LOAD_LIBRARY_SEARCH_SYSTEM32`], and [`LOAD_LIBRARY_SEARCH_USER_DIRS`]. Directories in the
+/// standard search path are not searched. This value cannot be combined with
+/// [`LOAD_WITH_ALTERED_SEARCH_PATH`].
+///
+/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
+pub const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: DWORD = consts::LOAD_LIBRARY_SEARCH_DEFAULT_DIRS;
+
+/// Directory that contains the DLL is temporarily added to the beginning of the list of
+/// directories that are searched for the DLL’s dependencies.
+///
+/// Directories in the standard search path are not searched.
+///
+/// The `filename` parameter must specify a fully qualified path. This value cannot be combined
+/// with [`LOAD_WITH_ALTERED_SEARCH_PATH`].
+///
+/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
+pub const LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR: DWORD = consts::LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR;
+
+/// Search `%windows%\system32` for the DLL and its dependencies.
+///
+/// Directories in the standard search path are not searched. This value cannot be combined with
+/// [`LOAD_WITH_ALTERED_SEARCH_PATH`].
+///
+/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
+pub const LOAD_LIBRARY_SEARCH_SYSTEM32: DWORD = consts::LOAD_LIBRARY_SEARCH_SYSTEM32;
+
+///  Directories added using the `AddDllDirectory` or the `SetDllDirectory` function are searched
+///  for the DLL and its dependencies.
+///
+///  If more than one directory has been added, the order in which the directories are searched is
+///  unspecified. Directories in the standard search path are not searched. This value cannot be
+///  combined with [`LOAD_WITH_ALTERED_SEARCH_PATH`].
+///
+/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
+pub const LOAD_LIBRARY_SEARCH_USER_DIRS: DWORD = consts::LOAD_LIBRARY_SEARCH_USER_DIRS;
+
+/// If `filename specifies an absolute path, the system uses the alternate file search strategy
+/// discussed in the [Remarks section] to find associated executable modules that the specified
+/// module causes to be loaded.
+///
+/// If this value is used and `filename` specifies a relative path, the behavior is undefined.
+///
+/// If this value is not used, or if `filename` does not specify a path, the system uses the
+/// standard search strategy discussed in the [Remarks section] to find associated executable
+/// modules that the specified module causes to be loaded.
+///
+/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
+///
+/// [Remarks]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#remarks
+pub const LOAD_WITH_ALTERED_SEARCH_PATH: DWORD = consts::LOAD_WITH_ALTERED_SEARCH_PATH;
+
+/// Specifies that the digital signature of the binary image must be checked at load time.
+///
+/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
+pub const LOAD_LIBRARY_REQUIRE_SIGNED_TARGET: DWORD = consts::LOAD_LIBRARY_REQUIRE_SIGNED_TARGET;
+
+/// Allow loading a DLL for execution from the current directory only if it is under a directory in
+/// the Safe load list.
+///
+/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
+pub const LOAD_LIBRARY_SAFE_CURRENT_DIRS: DWORD = consts::LOAD_LIBRARY_SAFE_CURRENT_DIRS;
diff --git a/src/test_helpers.rs b/src/test_helpers.rs
index 32f7023..9e3e992 100644
--- a/src/test_helpers.rs
+++ b/src/test_helpers.rs
@@ -1,7 +1,6 @@
 //! This is a separate file containing helpers for tests of this library. It is built into a
 //! dynamic library by the build.rs script.
-#![crate_type="dylib"] // FIXME: should become a cdylib in due time
-#![cfg_attr(test_nightly, feature(thread_local))]
+#![crate_type="cdylib"]
 
 #[no_mangle]
 pub static mut TEST_STATIC_U32: u32 = 0;
@@ -9,11 +8,6 @@
 #[no_mangle]
 pub static mut TEST_STATIC_PTR: *mut () = 0 as *mut _;
 
-#[cfg(test_nightly)]
-#[thread_local]
-#[no_mangle]
-pub static mut TEST_THREAD_LOCAL: u32 = 0;
-
 #[no_mangle]
 pub extern "C" fn test_identity_u32(x: u32) -> u32 {
     x
@@ -41,9 +35,3 @@
 pub unsafe extern "C" fn test_check_static_ptr() -> bool {
     TEST_STATIC_PTR == (&mut TEST_STATIC_PTR as *mut *mut _ as *mut _)
 }
-
-#[cfg(test_nightly)]
-#[no_mangle]
-pub unsafe extern "C" fn test_get_thread_local() -> u32 {
-    TEST_THREAD_LOCAL
-}
diff --git a/src/util.rs b/src/util.rs
index e5108c2..880b689 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -7,7 +7,7 @@
 /// Checks for last byte and avoids allocating if it is zero.
 ///
 /// Non-last null bytes still result in an error.
-pub(crate) fn cstr_cow_from_bytes<'a>(slice: &'a [u8]) -> Result<Cow<'a, CStr>, Error> {
+pub(crate) fn cstr_cow_from_bytes(slice: &[u8]) -> Result<Cow<'_, CStr>, Error> {
     static ZERO: raw::c_char = 0;
     Ok(match slice.last() {
         // Slice out of 0 elements
diff --git a/tests/constants.rs b/tests/constants.rs
new file mode 100644
index 0000000..ad910c4
--- /dev/null
+++ b/tests/constants.rs
@@ -0,0 +1,13 @@
+extern crate libloading;
+extern crate libc;
+extern crate static_assertions;
+
+#[cfg(all(test, unix))]
+mod unix {
+    use super::static_assertions::const_assert_eq;
+
+    const_assert_eq!(libloading::os::unix::RTLD_LOCAL, libc::RTLD_LOCAL);
+    const_assert_eq!(libloading::os::unix::RTLD_GLOBAL, libc::RTLD_GLOBAL);
+    const_assert_eq!(libloading::os::unix::RTLD_NOW, libc::RTLD_NOW);
+    const_assert_eq!(libloading::os::unix::RTLD_LAZY, libc::RTLD_LAZY);
+}
diff --git a/tests/functions.rs b/tests/functions.rs
index dece58c..b642478 100644
--- a/tests/functions.rs
+++ b/tests/functions.rs
@@ -1,19 +1,25 @@
+#[cfg(windows)]
+extern crate winapi;
+
 extern crate libloading;
 use libloading::{Symbol, Library};
 
-const LIBPATH: &'static str = concat!(env!("OUT_DIR"), "/libtest_helpers.dll");
+const LIBPATH: &'static str = concat!(env!("OUT_DIR"), "/libtest_helpers.module");
 
 fn make_helpers() {
     static ONCE: ::std::sync::Once = ::std::sync::Once::new();
     ONCE.call_once(|| {
-        let mut outpath = String::from(if let Some(od) = option_env!("OUT_DIR") { od } else { return });
         let rustc = option_env!("RUSTC").unwrap_or_else(|| { "rustc".into() });
-        outpath.push_str(&"/libtest_helpers.dll"); // extension for windows required, POSIX does not care.
-        let _ = ::std::process::Command::new(rustc)
+        let mut cmd = ::std::process::Command::new(rustc);
+        cmd
             .arg("src/test_helpers.rs")
             .arg("-o")
-            .arg(outpath)
-            .arg("-O")
+            .arg(LIBPATH)
+            .arg("--target")
+            .arg(env!("LIBLOADING_TEST_TARGET"))
+            .arg("-O");
+
+        cmd
             .output()
             .expect("could not compile the test helpers!");
     });
@@ -136,20 +142,69 @@
     }
 }
 
-#[cfg(any(windows, target_os="linux"))]
-#[cfg(test_nightly)]
+#[cfg(unix)]
 #[test]
-fn test_tls_static() {
+fn library_this_get() {
+    use libloading::os::unix::Library;
     make_helpers();
-    let lib = Library::new(LIBPATH).unwrap();
+    let _lib = Library::new(LIBPATH).unwrap();
+    let this = Library::this();
+    // SAFE: functions are never called
     unsafe {
-        let var: Symbol<*mut u32> = lib.get(b"TEST_THREAD_LOCAL\0").unwrap();
-        **var = 84;
-        let help: Symbol<unsafe extern fn() -> u32> = lib.get(b"test_get_thread_local\0").unwrap();
-        assert_eq!(84, help());
+        // Library we loaded in `_lib` (should be RTLD_LOCAL).
+        // FIXME: inconsistent behaviour between macos and other posix systems
+        // assert!(this.get::<unsafe extern "C" fn()>(b"test_identity_u32").is_err());
+        // Something obscure from libc...
+        assert!(this.get::<unsafe extern "C" fn()>(b"freopen").is_ok());
     }
-    ::std::thread::spawn(move || unsafe {
-        let help: Symbol<unsafe extern fn() -> u32> = lib.get(b"test_get_thread_local\0").unwrap();
-        assert_eq!(0, help());
-    }).join().unwrap();
+}
+
+#[cfg(windows)]
+#[test]
+fn library_this() {
+    use libloading::os::windows::Library;
+    make_helpers();
+    let _lib = Library::new(LIBPATH).unwrap();
+    let this = Library::this().expect("this library");
+    // SAFE: functions are never called
+    unsafe {
+        // Library we loaded in `_lib`.
+        assert!(this.get::<unsafe extern "C" fn()>(b"test_identity_u32").is_err());
+        // Something "obscure" from kernel32...
+        assert!(this.get::<unsafe extern "C" fn()>(b"GetLastError").is_err());
+    }
+}
+
+#[cfg(windows)]
+#[test]
+fn works_getlasterror() {
+    use winapi::um::errhandlingapi;
+    use winapi::shared::minwindef::DWORD;
+    use libloading::os::windows::{Library, Symbol};
+
+    let lib = Library::new("kernel32.dll").unwrap();
+    let gle: Symbol<unsafe extern "system" fn() -> DWORD> = unsafe {
+        lib.get(b"GetLastError").unwrap()
+    };
+    unsafe {
+        errhandlingapi::SetLastError(42);
+        assert_eq!(errhandlingapi::GetLastError(), gle())
+    }
+}
+
+#[cfg(windows)]
+#[test]
+fn works_getlasterror0() {
+    use winapi::um::errhandlingapi;
+    use winapi::shared::minwindef::DWORD;
+    use libloading::os::windows::{Library, Symbol};
+
+    let lib = Library::new("kernel32.dll").unwrap();
+    let gle: Symbol<unsafe extern "system" fn() -> DWORD> = unsafe {
+        lib.get(b"GetLastError\0").unwrap()
+    };
+    unsafe {
+        errhandlingapi::SetLastError(42);
+        assert_eq!(errhandlingapi::GetLastError(), gle())
+    }
 }
diff --git a/tests/library_filename.rs b/tests/library_filename.rs
new file mode 100644
index 0000000..efe51b8
--- /dev/null
+++ b/tests/library_filename.rs
@@ -0,0 +1,17 @@
+extern crate libloading;
+use libloading::library_filename;
+use std::path::Path;
+
+#[cfg(target_os = "windows")]
+const EXPECTED: &str = "audioengine.dll";
+#[cfg(target_os = "linux")]
+const EXPECTED: &str = "libaudioengine.so";
+#[cfg(target_os = "macos")]
+const EXPECTED: &str = "libaudioengine.dylib";
+
+#[test]
+fn test_library_filename() {
+    let name = "audioengine";
+    let resolved = library_filename(name);
+    assert!(Path::new(&resolved).ends_with(EXPECTED));
+}
diff --git a/tests/markers.rs b/tests/markers.rs
index 01da108..330c034 100644
--- a/tests/markers.rs
+++ b/tests/markers.rs
@@ -4,6 +4,23 @@
 fn assert_send<T: Send>() {}
 #[cfg(test)]
 fn assert_sync<T: Sync>() {}
+#[cfg(test)]
+fn assert_display<T: std::fmt::Display>() {}
+
+#[test]
+fn check_error_send() {
+    assert_send::<libloading::Error>();
+}
+
+#[test]
+fn check_error_sync() {
+    assert_sync::<libloading::Error>();
+}
+
+#[test]
+fn check_error_display() {
+    assert_display::<libloading::Error>();
+}
 
 #[test]
 fn check_library_send() {