From b6278280dcc5018f043a1112c003e31c8305edab Mon Sep 17 00:00:00 2001 From: Ganesh Viswanathan Date: Sun, 14 Jun 2020 16:10:34 -0500 Subject: [PATCH] Fix for Windows, README --- README.md | 11 ++++++----- nimterop/build.nim | 45 +++++++++++++++++++++++++++------------------ nimterop/conan.nim | 24 +++++++++++++++++------- 3 files changed, 50 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 48822ac..3fd48e2 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ getHeader( "header.h", # The header file to wrap, full path is returned in `headerPath` giturl = "https://github.com/username/repo", # Git repo URL dlurl = "https://website.org/download/repo-$1.tar.gz", # Download URL for archive or raw file + conanuri = "repo/$1", # Conan.io URI outdir = baseDir, # Where to download/build/search conFlags = "--disable-comp --enable-feature", # Flags to pass configure script cmakeFlags = "-DENABLE_STATIC_LIB=ON" # Flags to pass to Cmake @@ -61,7 +62,7 @@ getHeader( # Wrap headerPath as returned from getHeader() and link statically # or dynamically depending on user input -when not defined(headerStatic): +when not isDefined(headerStatic): cImport(headerPath, recurse = true, dynlib = "headerLPath") # Pass dynlib if not static link else: cImport(headerPath, recurse = true) @@ -74,8 +75,8 @@ Module documentation for the build API can be found [here](https://nimterop.gith The above wrapper is generic and allows the end user to control how it works. Note that `headerPath` is derived from `header.h` so if you have `SDL.h` as the argument to `getHeader()`, it generates `SDLPath` and `SDLLPath` and is controlled by `-d:SDLStatic`, `-d:SDLGit` and so forth. - If the library is already installed in `/usr/include` then the `-d:headerStd` define to Nim can be used to instruct `getHeader()` to search for `header.h` in the standard system path. -- If the library needs to be downloaded, the user can use `-d:headerGit` to clone the source from the specified git URL or `-d:headerDL` to get the source from download URL. - - The `-d:headerSetVer=X.Y.Z` flag can be used to specify which version to download. It is used as the tag name for Git whereas for DL, it replaces `$1` in the URL if defined. +- If the library needs to be downloaded, the user can use `-d:headerGit` to clone the source from the specified git URL, `-d:headerDL` to get the source from download URL or `-d:headerConan` to download from https://conan.io/center. + - The `-d:headerSetVer=X.Y.Z` flag can be used to specify which version to download. It is used as the tag name for Git and for DL and Conan, it replaces `$1` in the URL if specified. - If no flag is provided, `getHeader()` simply looks for the library in `outdir`. The user could use Git submodules or manually download or check-in the library to that directory and `getHeader()` will use it directly. #### Pre build @@ -92,7 +93,7 @@ Flags can be specified to these tools via `getHeader()` or directly via the unde #### Linking -- If `-d:headerStatic` is specified, `getHeader()` will return the static library path in `headerLPath`. The wrapper writer can check for this and call `cImport()` accordingly as in the example above. If it is omitted, the dynamic library is returned in `headerLPath`. +- If `-d:headerStatic` is specified, `getHeader()` will return the static library path in `headerLPath`. The wrapper writer can check for this and call `cImport()` accordingly as in the example above. If `-d:headerStatic` is omitted, the dynamic library is returned in `headerLPath`. - `getHeader()` searches for libraries based on the header name by default: - `libheader.so` or `libheader.a` on Linux - `libheader.dylib` on OSX @@ -224,7 +225,7 @@ Options: -n, --pnim bool false print Nim output -E=, --prefix= strings {} strip prefix from identifiers -p, --preprocess bool false run preprocessor on header - -r, --recurse bool false process #include files + -r, --recurse bool false process #include files, implies --preprocess -G=, --replace= strings {} replace X with Y in identifiers, X1=Y1,X2=Y2, @X for regex -s, --stub bool false stub out undefined type references as objects -F=, --suffix= strings {} strip suffix from identifiers diff --git a/nimterop/build.nim b/nimterop/build.nim index d534cf9..74e6a61 100644 --- a/nimterop/build.nim +++ b/nimterop/build.nim @@ -1044,32 +1044,41 @@ macro getHeader*( ## `-d:xxxStatic` can be specified to statically link with the library instead. This ## will automatically add a `{.passL.}` call to the static library for convenience. Note ## that `-d:xxxConan` downloads all dependency libs as well and the `xxxLPath` will - ## include all separated by space in the right order for linking. + ## include paths to all of them separated by space in the right order for linking. + ## + ## Note also that Conan currently builds all OSX binaries on 10.14 so older versions of + ## OSX will complain if statically linking to these binaries. Further, all Conan binaries + ## for Windows are built with Visual Studio so static linking the `.lib` files with gcc + ## or clang might lead to incompatibility issues if the library uses Visual Studio + ## specific compiler features. ## ## `conFlags`, `cmakeFlags` and `makeFlags` allow sending custom parameters to `configure`, - ## `cmake` and `make` in case additional configuration is required as part of the build process. + ## `cmake` and `make` in case additional configuration is required as part of the build + ## process. ## - ## `altNames` is a list of alternate names for the library - e.g. zlib uses `zlib.h` for the header but - ## the typical lib name is `libz.so` and not `libzlib.so`. However, it is libzlib.dll on Windows if built - ## with cmake. In this case, `altNames = "z,zlib"`. Comma separate for multiple alternate names without - ## spaces. + ## `altNames` is a list of alternate names for the library - e.g. zlib uses `zlib.h` for + ## the header but the typical lib name is `libz.so` and not `libzlib.so`. However, it is + ## libzlib.dll on Windows if built with cmake. In this case, `altNames = "z,zlib"`. Comma + ## separate for multiple alternate names without spaces. ## - ## The original header name is not included by default if `altNames` is set since it could cause the - ## wrong lib to be selected. E.g. `SDL2/SDL.h` could pick `libSDL.so` even if `altNames = "SDL2"`. - ## Explicitly include it in `altNames` like the `zlib` example when required. + ## The original header name is not included by default if `altNames` is set since it could + ## cause the wrong lib to be selected. E.g. `SDL2/SDL.h` could pick `libSDL.so` even if + ## `altNames = "SDL2"`. Explicitly include it in `altNames` like the `zlib` example when + ## required. ## - ## `buildTypes` specifies a list of ordered build strategies to use when building the downloaded source - ## files. Default is [btCmake, btAutoconf] + ## `buildTypes` specifies a list of ordered build strategies to use when building the + ## downloaded source files. Default is [btCmake, btAutoconf] ## - ## `xxxPreBuild` is a hook that is called after the source code is pulled from Git or downloaded but - ## before the library is built. This might be needed if some initial prep needs to be done before - ## compilation. A few values are provided to the hook to help provide context: + ## `xxxPreBuild` is a hook that is called after the source code is pulled from Git or + ## downloaded but before the library is built. This might be needed if some initial prep + ## needs to be done before compilation. A few values are provided to the hook to help + ## provide context: ## - ## `outdir` is the same `outdir` passed in and `header` is the discovered header path in the - ## downloaded source code. + ## `outdir` is the same `outdir` passed in and `header` is the discovered header path + ## in the downloaded source code. ## - ## Simply define `proc xxxPreBuild(outdir, header: string)` in the wrapper and it will get called - ## prior to the build process. + ## Simply define `proc xxxPreBuild(outdir, header: string)` in the wrapper and it will get + ## called prior to the build process. var origname = header.extractFilename().split(".")[0] name = origname.split(seps = AllChars-Letters-Digits).join() diff --git a/nimterop/conan.nim b/nimterop/conan.nim index e9d23cb..872d138 100644 --- a/nimterop/conan.nim +++ b/nimterop/conan.nim @@ -65,13 +65,19 @@ proc jsonGet(url: string): JsonNode = # Make HTTP call and return content as JSON let temp = getTempDir() - file = temp / url.extractFilename() + file = block: + var + file = temp / url.extractFilename() + when defined(Windows): + file = file.replace('?', '_') + file downloadUrl(url, temp, quiet = true) result = readFile(file).parseJson() rmFile(file) -proc `==`(pkg1, pkg2: ConanPackage): bool = +proc `==`*(pkg1, pkg2: ConanPackage): bool = + ## Check if two ConanPackage objects are equal (not pkg1.isNil and not pkg2.isNil and pkg1.name == pkg2.name and pkg1.version == pkg2.version and @@ -94,9 +100,7 @@ proc newConanPackage*(name, version, user = "_", channel = "_", bhash = "", shar result.shared = shared proc newConanPackageFromUri*(uri: string, shared = true): ConanPackage = - ## Create a new ConanPackage from a conan uri - ## - ## name/version[@user/channel][:bhash] + ## Create a new ConanPackage from a conan uri typically formatted as name/version[@user/channel][:bhash] var name, version, user, channel, bhash: string @@ -136,6 +140,8 @@ proc getUriFromConanPackage*(pkg: ConanPackage): string = proc searchConan*(name: string, version = "", user = "", channel = ""): ConanPackage = ## Search for package by `name` and optional `version`, `user` and `channel` + ## + ## Search is quite slow so it is preferable to specify a version and use `getConanBuilds()` var query = name if version.len != 0: @@ -249,7 +255,7 @@ proc getConanRevisions*(pkg: ConanPackage, bld: ConanBuild) = bld.revisions.add i.getOrDefault("revision").getStr() proc loadConanInfo*(outdir: string): ConanPackage = - ## Load cached package info from `outdir/conaninfo.txt` + ## Load cached package info from `outdir/conaninfo.json` fixOutDir() let file = outdir / conanInfo @@ -258,7 +264,7 @@ proc loadConanInfo*(outdir: string): ConanPackage = result = to[ConanPackage](readFile(file)) proc saveConanInfo*(pkg: ConanPackage, outdir: string) = - ## Save downloaded package info to `outdir/conaninfo.txt` + ## Save downloaded package info to `outdir/conaninfo.json` fixOutDir() let file = outdir / conanInfo @@ -266,6 +272,7 @@ proc saveConanInfo*(pkg: ConanPackage, outdir: string) = writeFile(file, $$pkg) proc parseConanManifest(pkg: ConanPackage, outdir: string) = + # Get all header and library info from downloaded conan package let file = outdir / conanManifest @@ -327,6 +334,9 @@ proc dlConanBuild*(pkg: ConanPackage, bld: ConanBuild, outdir: string, revision proc dlConanRequires*(pkg: ConanPackage, bld: ConanBuild, outdir: string) proc downloadConan*(pkg: ConanPackage, outdir: string, clean = true) = ## Download latest recipe/build/revision of `pkg` to `outdir` + ## + ## High-level API that handles the end to end Conan process flow to find + ## latest package binary and downloads and extracts it to `outdir`. fixOutDir() let pkg =