# DeviceAtlas C API and Windows # A how-to guide to compile and run the DeviceAtlas C API in a Windows environment. ## Requirements ## The following tools and libraries are required to build the C API. - [Cygwin](https://www.cygwin.com/) OR [MinGW](https://sourceforge.net/projects/mingw-w64/) - make - GCC 4.2 or above / Visual Studio 2015 or above - CMake >=2.8 - PCRE >=8.38 (minimum v8.21 for improved performance) or PCRE2 10.x (or above). ### Optional ### - CURL - OpenSSL or LibreSSL - libzip - zlib ### Setup ### #### Choosing between Cygwin and MinGW #### Either Cygwin or MinGW can be used to build the C API on Windows. The build process is more straightforward using Cygwin but execution of the API requires the cygwin1.dll file to be available via the PATH environment variable or from the System32/SysWOW64 directory. Cygwin has the advantage that it offers all the required build tools and also a pre-built PCRE/PCRE2 library removing the need to also build it. Building with MinGW requires some extra steps as it does not come bundled with CMake and typically also involves building PCRE/PCRE2 too. Once built, the API will run without any other DLL dependencies. The following section describes setting up the build environment for both Cygwin and MinGW. #### Cygwin Setup #### Download and install Cygwin. Please ensure that the Cygwin bin directory is added to the Windows PATH environment variable. Cygwin uses a GUI installer for choosing the packages to install. The following packages are required to build the C API: cmake, make, gcc-core, gcc-g++, libpcre-devel and libpcre1. These packages can be manually selected from the Cygwin installation GUI. Alternatively, the following command can be run via cmd.exe to select/install all the required dependencies in the Cygwin GUI: ```cmd C:\path\to\cygwinsetup> setup-x86.exe -q -P cmake -P make -P gcc-core -P gcc-g++ -P libpcre-devel -P libpcre1 ``` Note that the above command installs the required pre-built PCRE libraries so it is _not_ necessary to also build and install PCRE. **Important** - if the Cygwin bin directory is _not_ added to the Windows PATH environment variable and the API is run outside of the Cygwin shell then Windows may display an error like the following: "The program can't start because cygwin1.dll is missing from your computer." #### MinGW Setup #### An alternative to Cygwin is MinGW. MinGW is more minimalist than Cygwin and does not come with a pre-built PCRE library. Download and install [MinGW-w64](https://sourceforge.net/projects/mingw-w64/) and [CMake](https://cmake.org/). Please ensure that the bin directories for both MinGW and CMake are added to the Windows PATH environment variable. **Important** - There are multiple MinGW projects. The project [MinGW](http://mingw.org) is quite dated and it is recommended to use [MinGW-w64](https://sourceforge.net/projects/mingw-w64/) instead. Most of the commands in MinGW are consistent with Cygwin except for 'make'. Please use 'mingw32-make' instead. When using CMake, the default generator is typically NMake and not MinGW. It is important to specify MinGW as the generator to create the correct Makefiles. This is achieved with the -G parameter when running CMake: ``` % cmake -G "MinGW Makefiles" ``` #### Visual Studio Setup #### From the cmake configuration, it will generate the proper Visual Studio Solution, automatically setting the proper generator, eventually clarifying the architecture wished (e.g 32 bitson 64 bits target). It is highly recommended to use a modern package manager (e.g. [vcpkg](https://github.com/microsoft/vcpkg/releases), [conan](https://conan.io/downloads.html)) to be able to handle all necessary dependencies, for both 32 and 64 bits architectures. Both DLL and LIB are built, the former needs to be accessible from the Path environment var. Note in debug mode, pdb symbols files are recommended to be in same folder level as those libraries, dependencies and the api's. For DLL builds, the API's are compatible with the 64 bit ASLR linker flag. Note the overall performance might decrease depending on other factors. ``` % cmake -DPCRE_INCLUDE_DIR=<path to pcre include directory> -DCPRELIB=<path to pcre.lib> (Optional) [-DCURL_INCLUDE_DIR=<path to curl include directory> -DCURL_LIBRARY=<path to libcurl.lib>] [-DOPENSSL_ROOT_DIR=<path to openssl root install directory>] [-DZLIB_INCLUDE_DIR=<path to zlib include directory> -DZLIB_LIBRARY=<path to zlib.lib>] [-DZIP_INCLUDE_DIR=<path to libzip include directory> -DZIP_LIBRARY=<path to zip.lib>] ``` Note a script for vcpkg is proposed within the ExtraTools/Win32 folder, provided all dependencies have been installed beforehand. ``` % .\ExtraTools\Win32\createproject_vcpkg.bat <absolute path to the vcpkg installation> ``` ### PCRE/PCRE2 ### The DeviceAtlas C API uses a highly optimized trie structure. However, some operations also require the use of the PCRE regex library. PCRE is required to build and run the C API. It is recommended to use a pre-built PCRE/PCRE2 package. Cygwin provides a pre-built PCRE/PCRE2 library but MinGW does not. There are third party pre-built PCRE/PCRE2 libraries available for MinGW. Depending on your settings the built PCRE DLL library would be located in &lt;Disk drive&gt;:\Windows\\(SysWOW64|System32) or /usr/lib **Important** - The PCRE for Windows library found at [PCRE for Windows package](http://gnuwin32.sourceforge.net/packages/pcre.htm) is obsolete and should not be used. #### Building PCRE/PCRE2 #### If a pre-built PCRE/PCRE2 library is not available it can be built from source. The source code is available from the [PCRE/PCRE2 FTP server](ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/). The typical build process is as follows but please note differences when using MinGW. ```cmd C:\> cd <path to pcre source> C:\path\to\pcre\> cmake -DNON_STANDARD_LIB_PREFIX=1 C:\path\to\pcre\> make ``` To build using MinGW: ```cmd C:\> cd <path to pcre source> C:\path\to\pcre\> cmake -G "MinGW Makefiles" -DNON_STANDARD_LIB_PREFIX=1 -DBUILD_SHARED_LIBS=1 C:\path\to\pcre\> mingw32-make ``` The above should produce a pcre.dll file. It is recommended to place this in the Windows System32 or SysWOW64 directory. ## Building the DeviceAtlas C API ## The process to build the DeviceAtlas C API is straightforward but there are small differences if using Cygwin or MinGW. ### Building using Cygwin ### The build process using Cygwin assumes that the pre-built PCRE package were installed using the Cygwin installer. Building the C API with Cygwin: ```cmd C:\> cd <path to C API> C:\path\to\c-api\> cmake . C:\path\to\c-api\> make ``` The build process should have produced DeviceAtlas libraries (libda.dll, libda.dll.a) and Carrier API libraries (libci.dll, libci.dll.a). The execution of the API can be verified by trying some of the example applications. See the examples section below. In order for the DeviceAtlas and Carrier APIs provided examples to work, the produced libraries (libda.dll, libci.dll) should be placed on the working path or copied to the working folder. ```cmd C:\path\to\c-api\> cp .\Src\libci.dll .\Src\libda.dll .\Examples ``` ### Building using MinGW ### The build process using MinGW assume that a custom PCRE library has been built from source and that the resulting pcre.dll file has been placed in either the System32 or SysWOW64 directory. Note that the path to the extracted PCRE archive is required for the PCRE headers. **Important** - Some versions of MinGW do not have the necessary functions to build the examples bundled with the C API. The CMakeLists.txt file can be edited to disable the compilation of the examples if MinGW cannot compile all the examples. This can be achieved by commenting out the examples line: ```(line 32) #add_subdirectory(examples)``` Building the C API with MinGW: ```cmd C:\> cd <path to C API> C:\path\to\c-api\> cmake -G "MinGW Makefiles" -DPCRE_INCLUDE_DIR=C:\path\to\pcre C:\path\to\c-api\> mingw32-make ``` The build process should have produced DeviceAtlas libraries (libda.dll, libda.dll.a) and Carrier API libraries (libci.dll, libci.dll.a). The execution of the API can be verified by trying some of the example applications. See the examples section below. Note that example0 should be compatible with all versions of MinGW. In order for the DeviceAtlas and Carrier APIs provided examples to work, the produced libraries (libda.dll, libci.dll) should be placed on the working path or copied to the working folder. ```cmd C:\path\to\c-api\> cp .\Src\libci.dll .\Src\libda.dll .\Examples ``` ### Further considerations ### For integration into other C or C++ applications the DeviceAtlas headers and resulting library are required. For integration into a .NET application only the libda.dll library file is required. By default, cmake will look for the PCRE DLL in one of the standard locations mentioned above. If the PCRE DLL is in a custom location the cmake variables PCRE_INCLUDE_DIR and PCRELIB should be used when building DeviceAtlas. For example: ```cmd % cmake -DPCRE_INCLUDE_DIR=/opt/local/include -DPCRELIB=/opt/local/lib/libpcre.dll.a ``` ### Updating the API ### Normally the PCRE library does not need to be rebuilt when updating the DeviceAtlas C API and can be deployed across Win32 ABI compatible machines. The steps outlined above are the same for building a new C API version. ## Examples ## Examples can be found in the Examples subfolder of the C API package. Please ensure the DeviceAtlas data file has been downloaded and extracted. The following shows how to run an example using cmd.exe shell: ```cmd C:\> cd <path to C API>\Examples\device\getproperties C:\path\to\c\api> cmake . && make && ./main <path to a data file> <user agent> e.g. C:\path\to\c\api> .main ..\20200301.json "Mozilla/5.0 (Linux; Android 4.2.2; HTC One Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.92 Mobile Safari/537.36" ``` Please note that example 4 shows how to hot-swap the data file for minimal impact when updating the data file. ## Integration with .NET technologies ## The built API can be called from .NET code via the the [DllImport feature][1] and the [P/Invoke mechanism][2] (compatible with Microsoft .NET, .NET Core and Mono). The following functions need to be imported to have a minimum of functionality: - [da_init](https://docs.deviceatlas.com/apis/enterprise/c/2.1/ApiDocs/dac_8h_ae6a83d2bee98adb88bf65dc0e8aa5579.html#ae6a83d2bee98adb88bf65dc0e8aa5579) - [da_fini](https://docs.deviceatlas.com/apis/enterprise/c/2.1/ApiDocs/dac_8h_a447d58ebd472a2cb070d0c64666aaaf2.html#a447d58ebd472a2cb070d0c64666aaaf2) - [da_atlas_header_evidence_id](https://docs.deviceatlas.com/apis/enterprise/c/2.1/ApiDocs/dac_8h_a019442ae3fde38aa28b254b21bf9e269.html#a019442ae3fde38aa28b254b21bf9e269) - [da_atlas_compile](https://docs.deviceatlas.com/apis/enterprise/c/2.1/ApiDocs/dac_8h_adcb1c8fec0ee9bf80ccaa4f289bcc204.html#adcb1c8fec0ee9bf80ccaa4f289bcc204) - [da_atlas_open](https://docs.deviceatlas.com/apis/enterprise/c/2.1/ApiDocs/dac_8h_a2eb87ba7f137f2f541eb1087722af066.html#a2eb87ba7f137f2f541eb1087722af066) - [da_atlas_close](https://docs.deviceatlas.com/apis/enterprise/c/2.1/ApiDocs/dac_8h_aeb1e01f371623217f7a60625b078cc2f.html#aeb1e01f371623217f7a60625b078cc2f) - [da_searchv](https://docs.deviceatlas.com/apis/enterprise/c/2.1/ApiDocs/dac_8h_a37b2349f4fddc3967e740304a706f621.html#a37b2349f4fddc3967e740304a706f621) - [da_search](https://docs.deviceatlas.com/apis/enterprise/c/2.1/ApiDocs/dac_8h_a631d0feb27811b79aa1147f508711172.html#a631d0feb27811b79aa1147f508711172) - [da_close](https://docs.deviceatlas.com/apis/enterprise/c/2.1/ApiDocs/dac_8h_a6f206c4d51ea77bf37c48170a609f94d.html#a6f206c4d51ea77bf37c48170a609f94d) - [da_getpropstring](https://docs.deviceatlas.com/apis/enterprise/c/2.1/ApiDocs/dac_8h_ae5902fa6e81257a7549d845a5c781910.html#ae5902fa6e81257a7549d845a5c781910) - [da_getpropinteger](https://docs.deviceatlas.com/apis/enterprise/c/2.1/ApiDocs/dac_8h_a476aa987cf78c72941b9fefee6e55b10.html#a476aa987cf78c72941b9fefee6e55b10) - [da_getpropboolean](https://docs.deviceatlas.com/apis/enterprise/c/2.1/ApiDocs/dac_8h_a2a4ae76b9d8f8bb018fb88e671e81828.html#a2a4ae76b9d8f8bb018fb88e671e81828) - [da_getproptype](https://docs.deviceatlas.com/apis/enterprise/c/2.1/ApiDocs/dac_8h_a69f0a2059c442541cdfe75e5afceac63.html#a69f0a2059c442541cdfe75e5afceac63) - [da_getpropname](https://docs.deviceatlas.com/apis/enterprise/c/2.1/ApiDocs/dac_8h_a9aa5c02de0e81aaa1dae0bf01b520947.html#a9aa5c02de0e81aaa1dae0bf01b520947) - [da_getfirstprop](https://docs.deviceatlas.com/apis/enterprise/c/2.1/ApiDocs/dac_8h_a9179c4a47073592090f7639f1d3964fb.html#a9179c4a47073592090f7639f1d3964fb) - [da_getnextprop](https://docs.deviceatlas.com/apis/enterprise/c/2.1/ApiDocs/dac_8h_a6ff9e48dcc53b7031e589b5ee2c4ad67.html#a6ff9e48dcc53b7031e589b5ee2c4ad67) - [da_getpropcount](https://docs.deviceatlas.com/apis/enterprise/c/2.1/ApiDocs/dac_8h_a259737627eebea4cd418610d6ea8677d.html#a259737627eebea4cd418610d6ea8677d) If logging of API errors is required, these functions are also necessary: - [da_reporterror](https://docs.deviceatlas.com/apis/enterprise/c/2.1/ApiDocs/dac_8h_a89bb11ba0d89ed51f7852fd439ab5e54.html#a89bb11ba0d89ed51f7852fd439ab5e54) - [da_seterrorfunc](https://docs.deviceatlas.com/apis/enterprise/c/2.1/ApiDocs/dac_8h_a957e72f600e612b09e326f8e86bb8d58.html#a957e72f600e612b09e326f8e86bb8d58) [1]:https://msdn.microsoft.com/en-us/library/aa984739(v=vs.71).aspx [2]:https://msdn.microsoft.com/en-us/library/aa288468(v=vs.71).aspx **Important** - Care must be taken when casting between safe/unsafe code in .NET. Various flat C types (mainly numeric or enum) are used widely in the API and can be cast to their managed .NET types counterpart directly like da_evidence_id_t, da_propid_t, even da_status_t, da_severity_t etc. Most of the structs used to load the data in memory or for the detection might not be castable so it may be necessary to wrap them separately. There is only one raw C pointer to carry over the lifetime of the object owner which would need to be freed in the destructor. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - _ Copyright (c) DeviceAtlas Limited 2021. All Rights Reserved. _ https://deviceatlas.com <!-- HTML+JS for document formatting when opened in browser --> <div class="btn-group" id="main-menu" style="float:right"><a class="btn dropdown-toggle" data-toggle="dropdown" href="#">Menu<span class="caret"></span></a><ul class="dropdown-menu"><li><a href="README.html">Main</a></li><li class="divider"></li><li><a href="README.DeviceApi-Web.html">Device Detection for Web</a></li><li><a href="README.DeviceApi-Apps.html">Device Detection for Apps</a></li><li><a href="README.DeviceApi-Config.html">Device Detection API Config</a></li><li><a href="README.CarrierApi.html">Carrier Identification API</a></li><li class="divider"></li><li><a href="README.Unix.html">C API and Unix</a></li><li class="disabled"><a href="README.Windows.html">C API and Windows</a></li><li class="divider"></li><li><a href="README.Nginx.html">C API and NGINX Module Installation</a></li><li class="divider"></li><li><a href="README.JsonConverter.html">C API JSONConverter</a></li><li><a href="https://docs.deviceatlas.com/apis/clientside/latest/README.ClientSide.html" target="_blank">Client-side Component</a></li><li><a href="README.ConnectivityAnalyser-Nginx.html">NGINX DeviceAtlas Connectivity Analyser</a></li><li><a href="README.ConnectivityAnalyser-Apache.html">Apache DeviceAtlas Connectivity Analyser</a></li><li><a href="ApiDocs/index.html">DeviceAtlas ApiDocs</a></li></ul></div>