diff --git a/CMakeLists.txt b/CMakeLists.txt
index 739edeb..4cf9ef9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -111,6 +111,7 @@ if(WIN32)
# TODO fix and use windows flags
set(CMAKE_EXE_LINKER_FLAGS
"${CMAKE_EXE_LINKER_FLAGS} ${WINDOWS_LINKER_FLAGS}")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WINDOWS_FLAGS}")
endif()
set(OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/output")
diff --git a/README.md b/README.md
index 0f0c9e8..e634838 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,7 @@
[](https://circleci.com/gh/spotify/NFHTTP/tree/master)
+[](https://ci.appveyor.com/project/8W9aG/nfhttp/branch/master)
[](LICENSE)
[](https://slackin.spotify.com)
[](http://clayallsopp.github.io/readme-score?url=https://github.com/spotify/nfhttp)
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 0000000..485d2ff
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,10 @@
+image:
+- Visual Studio 2017
+
+build_script:
+- git submodule update --init --recursive
+- ps: ci/windows.ps1
+
+artifacts:
+ - path: build/output/libNFHTTP.zip
+ name: libNFHTTP.zip
diff --git a/ci/nfbuildwindows.py b/ci/nfbuildwindows.py
index 0999e17..ee61fce 100644
--- a/ci/nfbuildwindows.py
+++ b/ci/nfbuildwindows.py
@@ -17,104 +17,8 @@ class NFBuildWindows(NFBuild):
def __init__(self):
super(self.__class__, self).__init__()
self.project_file = 'build.ninja'
-
- def installClangFormat(self):
- clang_format_vulcan_file = os.path.join('tools', 'clang-format.vulcan')
- clang_format_extraction_folder = self.vulcanDownload(
- clang_format_vulcan_file,
- 'clang-format-5.0.0')
- self.clang_format_binary = os.path.join(
- os.path.join(
- os.path.join(
- clang_format_extraction_folder,
- 'clang-format'),
- 'bin'),
- 'clang-format')
-
- def installNinja(self):
- ninja_vulcan_file = os.path.join(
- os.path.join(
- os.path.join(
- os.path.join('tools', 'buildtools'),
- 'spotify_buildtools'),
- 'software'),
- 'ninja.vulcan')
- ninja_extraction_folder = self.vulcanDownload(
- ninja_vulcan_file,
- 'ninja-1.6.0')
- self.ninja_binary = os.path.join(
- ninja_extraction_folder,
- 'ninja')
- if 'PATH' not in os.environ:
- os.environ['PATH'] = ''
- if len(os.environ['PATH']) > 0:
- os.environ['PATH'] += os.pathsep
- os.environ['PATH'] += ninja_extraction_folder
-
- def installMake(self):
- make_vulcan_file = os.path.join('tools', 'make.vulcan')
- make_extraction_folder = self.vulcanDownload(
- make_vulcan_file,
- 'make-4.2.1')
- make_bin_folder = os.path.join(
- make_extraction_folder,
- 'bin')
- os.environ['PATH'] += os.pathsep + make_bin_folder
-
- def installVisualStudio(self):
- vs_vulcan_file = os.path.join(
- os.path.join(
- os.path.join(
- os.path.join('tools', 'buildtools'),
- 'spotify_buildtools'),
- 'software'),
- 'visualstudio.vulcan')
- self.vs_extraction_folder = self.vulcanDownload(
- vs_vulcan_file,
- 'visualstudio-2017')
- sdk_version = '10.0.15063.0'
- vc_tools_version = '14.10.25017'
- vc_redist_version = '14.10.25008'
- vc_redist_crt = 'Microsoft.VC150.CRT'
- vs_root = self.vs_extraction_folder
- sdk_root = os.path.join(vs_root, 'win10sdk')
- vc_root = os.path.join(vs_root, 'VC')
- vc_tools_root = os.path.join(vc_root, 'Tools', 'MSVC')
- vc_redist_root = os.path.join(vc_root, 'Redist', 'MSVC')
- os.environ['VS_ROOT'] = vs_root
- os.environ['SDK_ROOT'] = sdk_root
- os.environ['INCLUDE'] = os.pathsep.join([
- os.path.join(sdk_root, 'Include', sdk_version, 'um'),
- os.path.join(sdk_root, 'Include', sdk_version, 'ucrt'),
- os.path.join(sdk_root, 'Include', sdk_version, 'shared'),
- os.path.join(sdk_root, 'Include', sdk_version, 'winrt'),
- os.path.join(vc_tools_root, vc_tools_version, 'include'),
- os.path.join(vc_tools_root, vc_tools_version, 'atlmfc', 'include'),
- os.environ.get('INCLUDE', '')])
- os.environ['PATH'] = os.pathsep.join([
- os.path.join(sdk_root, 'bin', sdk_version, 'x86'),
- os.path.join(vc_tools_root, vc_tools_version, 'bin', 'HostX64', 'x86'),
- os.path.join(vc_tools_root, vc_tools_version, 'bin', 'HostX64', 'x64'),
- os.path.join(vc_redist_root, vc_redist_version, 'x64', vc_redist_crt),
- os.path.join(vs_root, 'SystemCRT'),
- os.environ.get('PATH', '')])
- os.environ['LIB'] = os.pathsep.join([
- os.path.join(sdk_root, 'Lib', sdk_version, 'um', 'x86'),
- os.path.join(sdk_root, 'Lib', sdk_version, 'ucrt', 'x86'),
- os.path.join(vc_tools_root, vc_tools_version, 'lib', 'x86'),
- os.path.join(vc_tools_root, vc_tools_version, 'atlmfc', 'lib', 'x86'),
- os.environ.get('LIB', '')])
- os.environ['LIBPATH'] = os.pathsep.join([
- os.path.join(vc_tools_root, vc_tools_version, 'lib', 'x86', 'store', 'references'),
- os.path.join(sdk_root, 'UnionMetadata', sdk_version),
- os.environ.get('LIBPATH', '')])
-
- def installVulcanDependencies(self, android=False):
- super(self.__class__, self).installVulcanDependencies(android)
- self.installClangFormat()
- self.installMake()
- self.installVisualStudio()
- self.installNinja()
+ self.cmake_binary = 'cmake'
+ self.android = False
def generateProject(self,
ios=False,
@@ -124,7 +28,7 @@ def generateProject(self,
cmake_call = [
self.cmake_binary,
'..',
- '-GNinja']
+ '-G']
if android or android_arm:
android_abi = 'x86_64'
android_toolchain_name = 'x86_64-llvm'
@@ -132,6 +36,7 @@ def generateProject(self,
android_abi = 'arm64-v8a'
android_toolchain_name = 'arm64-llvm'
cmake_call.extend([
+ 'Ninja',
'-DANDROID=1',
'-DCMAKE_TOOLCHAIN_FILE=' + self.android_ndk_folder + '/build/cmake/android.toolchain.cmake',
'-DANDROID_NDK=' + self.android_ndk_folder,
@@ -142,27 +47,29 @@ def generateProject(self,
'-DANDROID_STL=c++_shared'])
self.project_file = 'build.ninja'
else:
- cl_exe = os.path.join(self.vs_extraction_folder, 'VC', 'Tools', 'MSVC', '14.10.25017', 'bin', 'HostX64', 'x86', 'cl.exe').replace('\\', '/')
- rc_exe = os.path.join(self.vs_extraction_folder, 'win10sdk', 'bin', '10.0.15063.0', 'x64', 'rc.exe').replace('\\', '/')
- link_exe = os.path.join(self.vs_extraction_folder, 'VC', 'Tools', 'MSVC', '14.10.25017', 'bin', 'HostX64', 'x86', 'link.exe').replace('\\', '/')
cmake_call.extend([
- '-DCMAKE_C_COMPILER=' + cl_exe,
- '-DCMAKE_CXX_COMPILER=' + cl_exe,
- '-DCMAKE_RC_COMPILER=' + rc_exe,
- '-DCMAKE_LINKER=' + link_exe,
- '-DWINDOWS=1'])
+ 'Visual Studio 15 2017 Win64',
+ '-DCMAKE_SYSTEM_NAME=WindowsStore',
+ '-DCMAKE_SYSTEM_VERSION=10.0'])
cmake_result = subprocess.call(cmake_call, cwd=self.build_directory)
if cmake_result != 0:
sys.exit(cmake_result)
def buildTarget(self, target, sdk='macosx', arch='x86_64'):
- result = subprocess.call([
- self.ninja_binary,
- '-C',
- self.build_directory,
- '-f',
- self.project_file,
- target])
+ result = 0
+ if self.android:
+ result = subprocess.call([
+ self.ninja_binary,
+ '-C',
+ self.build_directory,
+ '-f',
+ self.project_file,
+ target])
+ else:
+ result = subprocess.call([
+ 'msbuild.exe',
+ os.path.join(self.build_directory, 'NFHTTP.sln'),
+ '/t:NFHTTP;' + target])
if result != 0:
sys.exit(result)
@@ -192,3 +99,22 @@ def runIntegrationTests(self):
if cli_result:
sys.exit(cli_result)
+ def packageArtifacts(self):
+ lib_name = 'NFHTTP.lib'
+ cli_name = 'NFHTTPCLI.exe'
+ output_folder = os.path.join(self.build_directory, 'output')
+ artifacts_folder = os.path.join(output_folder, 'NFHTTP')
+ shutil.copytree('include', os.path.join(artifacts_folder, 'include'))
+ source_folder = os.path.join(self.build_directory, 'source')
+ lib_matches = self.find_file(source_folder, lib_name)
+ cli_matches = self.find_file(source_folder, cli_name)
+ shutil.copyfile(lib_matches[0], os.path.join(artifacts_folder, lib_name))
+ if not self.android:
+ shutil.copyfile(cli_matches[0], os.path.join(artifacts_folder, cli_name))
+ output_zip = os.path.join(output_folder, 'libNFHTTP.zip')
+ self.make_archive(artifacts_folder, output_zip)
+ if self.android:
+ final_zip_name = 'libNFHTTP-androidx86.zip'
+ if self.android_arm:
+ final_zip_name = 'libNFHTTP-androidArm64.zip'
+ shutil.copyfile(output_zip, final_zip_name)
diff --git a/ci/windows.ps1 b/ci/windows.ps1
index ce5c670..aa93a8e 100644
--- a/ci/windows.ps1
+++ b/ci/windows.ps1
@@ -1,41 +1,66 @@
+<#
+ * Copyright (c) 2018 Spotify AB.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ #>
param (
[string]$build = "windows"
)
+Add-Type -AssemblyName System.IO.Compression.FileSystem
+
Write-Host "NFHTTP build process starting..."
Write-Host $build
-$ErrorActionPreference = "Stop"
-
try
{
- # Get python version
- $python_version = python --version
- Write-Host $python_version
+ # Upgrade pip or else the CI will complain
+ c:\python27\python.exe -m pip install --upgrade pip
+
+ $BoostFoldername = Join-Path $PSScriptRoot "boost_1_64_0"
+ $BoostZipname = Join-Path $PSScriptRoot "boost_1_64_0.zip"
+ wget https://dl.bintray.com/boostorg/release/1.64.0/source/boost_1_64_0.zip -OutFile $BoostZipname
+ [System.IO.Compression.ZipFile]::ExtractToDirectory($BoostZipname, $BoostFoldername)
+ $env:BOOST_ROOT = $BoostFoldername
# Start virtualenv
- $virtualenv_vulcan_output = python tools/vulcan/bin/vulcan.py -v -f tools/virtualenv.vulcan -p virtualenv-15.1.0
- $virtualenv_bin = Join-Path $virtualenv_vulcan_output /virtualenv-15.1.0/virtualenv.py
- python $virtualenv_bin nfdriver_env
+ pip install virtualenv
+ virtualenv nfhttp_env
- & ./nfdriver_env/Scripts/activate.bat
+ & ./nfhttp_env/Scripts/activate.bat
# Install Python Packages
- & nfdriver_env/Scripts/pip.exe install urllib3
- & nfdriver_env/Scripts/pip.exe install pyyaml
- & nfdriver_env/Scripts/pip.exe install flake8
+ & nfhttp_env/Scripts/pip.exe install urllib3 `
+ pyyaml `
+ flake8 `
+ cmakelint
if($build -eq "android"){
- & nfdriver_env/Scripts/python.exe ci/androidwindows.py
+ & nfhttp_env/Scripts/python.exe ci/androidwindows.py
} else {
- & nfdriver_env/Scripts/python.exe ci/windows.py
+ & nfhttp_env/Scripts/python.exe ci/windows.py build
}
if($LASTEXITCODE -ne 0){
exit $LASTEXITCODE
}
- & ./nfdriver_env/Scripts/deactivate.bat
+ & ./nfhttp_env/Scripts/deactivate.bat
}
catch
{
diff --git a/ci/windows.py b/ci/windows.py
index a027b15..90d5511 100644
--- a/ci/windows.py
+++ b/ci/windows.py
@@ -1,24 +1,71 @@
#!/usr/bin/env python
+'''
+ * Copyright (c) 2018 Spotify AB.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+'''
import sys
from nfbuildwindows import NFBuildWindows
+from build_options import BuildOptions
def main():
+ buildOptions = BuildOptions()
+ buildOptions.addOption("makeBuildDirectory",
+ "Wipe existing build directory")
+ buildOptions.addOption("generateProject", "Regenerate project")
+ buildOptions.addOption("buildTargetCLI",
+ "Build Target: CLI")
+ buildOptions.addOption("buildTargetLibrary", "Build Target: Library")
+ buildOptions.addOption("packageArtifacts", "Package the binary artifacts")
+ buildOptions.setDefaultWorkflow("Empty workflow", [])
+
+ buildOptions.addWorkflow("build", "Production Build", [
+ 'makeBuildDirectory',
+ 'generateProject',
+ 'buildTargetCLI',
+ 'buildTargetLibrary',
+ 'packageArtifacts'
+ ])
+
+ options = buildOptions.parseArgs()
+ buildOptions.verbosePrintBuildOptions(options)
+
library_target = 'NFHTTP'
cli_target = 'NFHTTPCLI'
nfbuild = NFBuildWindows()
- nfbuild.build_print("Installing Dependencies")
- nfbuild.installDependencies()
- # Make our main build artifacts
- nfbuild.build_print("C++ Build Start (x86)")
- nfbuild.makeBuildDirectory()
- nfbuild.generateProject()
- targets = [library_target, cli_target]
- for target in targets:
- nfbuild.buildTarget(target)
- # nfbuild.runIntegrationTests()
+
+ if buildOptions.checkOption(options, 'makeBuildDirectory'):
+ nfbuild.makeBuildDirectory()
+
+ if buildOptions.checkOption(options, 'generateProject'):
+ nfbuild.generateProject(ios=True)
+
+ if buildOptions.checkOption(options, 'buildTargetLibrary'):
+ nfbuild.buildTarget(library_target)
+
+ if buildOptions.checkOption(options, 'buildTargetCLI'):
+ nfbuild.buildTarget(cli_target)
+
+ if buildOptions.checkOption(options, "packageArtifacts"):
+ nfbuild.packageArtifacts()
if __name__ == "__main__":
diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt
index 42d5b94..da7db08 100644
--- a/libraries/CMakeLists.txt
+++ b/libraries/CMakeLists.txt
@@ -17,7 +17,7 @@
# specific language governing permissions and limitations
# under the License.
add_library(sqlite "${CMAKE_CURRENT_SOURCE_DIR}/sqlite/sqlite3.c")
-target_compile_definitions(sqlite PUBLIC -DSQLITE_THREADSAFE=2)
+target_compile_definitions(sqlite PUBLIC -DSQLITE_THREADSAFE=2 -DSQLITE_OS_WINRT=1)
set(BOOST_MAJOR 1)
set(BOOST_MINOR 64)
@@ -1107,6 +1107,6 @@ if(USE_CPPRESTSDK)
set(CPPREST_INSTALL_HEADERS OFF CACHE BOOL "Don't install headers" FORCE)
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build cpprest as a static lib" FORCE)
set(CPPREST_EXCLUDE_COMPRESSION ON CACHE BOOL "Exclude compression functionality." FORCE)
- add_definitions(-DSSL_R_SHORT_READ)
+ add_definitions(-DSSL_R_SHORT_READ -DNOMINMAX)
add_subdirectory(cpprestsdk/Release)
endif()
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
index b74b577..00aa355 100644
--- a/source/CMakeLists.txt
+++ b/source/CMakeLists.txt
@@ -116,3 +116,7 @@ target_link_libraries(NFHTTPCLI NFHTTP nlohmann_json)
if(USE_CURL)
target_compile_definitions(NFHTTP PRIVATE USE_CURL=1)
endif()
+
+if(WIN32)
+ target_compile_definitions(NFHTTP PRIVATE _CRT_SECURE_NO_WARNINGS)
+endif()
diff --git a/source/CacheLocationWindows.cpp b/source/CacheLocationWindows.cpp
index 7cf2fcb..96b0214 100644
--- a/source/CacheLocationWindows.cpp
+++ b/source/CacheLocationWindows.cpp
@@ -25,6 +25,8 @@
#include
#include
#include
+#include
+#include
namespace nativeformat {
namespace http {
diff --git a/source/CachingSQLiteDatabase.cpp b/source/CachingSQLiteDatabase.cpp
index 7fc6c50..b527c0b 100644
--- a/source/CachingSQLiteDatabase.cpp
+++ b/source/CachingSQLiteDatabase.cpp
@@ -26,6 +26,26 @@
#include
#include
+#if defined(_WIN32) || defined(WIN32)
+extern "C" char* strptime(const char* s,
+ const char* f,
+ struct tm* tm) {
+ // Isn't the C++ standard lib nice? std::get_time is defined such that its
+ // format parameters are the exact same as strptime. Of course, we have to
+ // create a string stream first, and imbue it with the current C locale, and
+ // we also have to make sure we return the right things if it fails, or
+ // if it succeeds, but this is still far simpler an implementation than any
+ // of the versions in any of the C standard libraries.
+ std::istringstream input(s);
+ input.imbue(std::locale(setlocale(LC_ALL, nullptr)));
+ input >> std::get_time(tm, f);
+ if (input.fail()) {
+ return nullptr;
+ }
+ return (char*)(s + input.tellg());
+}
+#endif
+
namespace nativeformat {
namespace http {