| #!/bin/bash |
| ## |
| ## Copyright (c) 2013 The WebM project authors. All Rights Reserved. |
| ## |
| ## Use of this source code is governed by a BSD-style license |
| ## that can be found in the LICENSE file in the root of the source |
| ## tree. An additional intellectual property rights grant can be found |
| ## in the file PATENTS. All contributing project authors may |
| ## be found in the AUTHORS file in the root of the source tree. |
| ## |
| |
| |
| self=$0 |
| self_basename=${self##*/} |
| self_dirname=$(dirname "$0") |
| EOL=$'\n' |
| |
| show_help() { |
| cat <<EOF |
| Usage: ${self_basename} --name=projname [options] file1 [file2 ...] |
| |
| This script generates a Visual Studio project file from a list of source |
| code files. |
| |
| Options: |
| --help Print this message |
| --exe Generate a project for building an Application |
| --lib Generate a project for creating a static library |
| --dll Generate a project for creating a dll |
| --static-crt Use the static C runtime (/MT) |
| --target=isa-os-cc Target specifier (required) |
| --out=filename Write output to a file [stdout] |
| --name=project_name Name of the project (required) |
| --proj-guid=GUID GUID to use for the project |
| --module-def=filename File containing export definitions (for DLLs) |
| --ver=version Version (10,11,12) of visual studio to generate for |
| --src-path-bare=dir Path to root of source tree |
| -Ipath/to/include Additional include directories |
| -DFLAG[=value] Preprocessor macros to define |
| -Lpath/to/lib Additional library search paths |
| -llibname Library to link against |
| EOF |
| exit 1 |
| } |
| |
| die() { |
| echo "${self_basename}: $@" >&2 |
| exit 1 |
| } |
| |
| die_unknown(){ |
| echo "Unknown option \"$1\"." >&2 |
| echo "See ${self_basename} --help for available options." >&2 |
| exit 1 |
| } |
| |
| generate_uuid() { |
| local hex="0123456789ABCDEF" |
| local i |
| local uuid="" |
| local j |
| #93995380-89BD-4b04-88EB-625FBE52EBFB |
| for ((i=0; i<32; i++)); do |
| (( j = $RANDOM % 16 )) |
| uuid="${uuid}${hex:$j:1}" |
| done |
| echo "${uuid:0:8}-${uuid:8:4}-${uuid:12:4}-${uuid:16:4}-${uuid:20:12}" |
| } |
| |
| indent1=" " |
| indent="" |
| indent_push() { |
| indent="${indent}${indent1}" |
| } |
| indent_pop() { |
| indent="${indent%${indent1}}" |
| } |
| |
| tag_attributes() { |
| for opt in "$@"; do |
| optval="${opt#*=}" |
| [ -n "${optval}" ] || |
| die "Missing attribute value in '$opt' while generating $tag tag" |
| echo "${indent}${opt%%=*}=\"${optval}\"" |
| done |
| } |
| |
| open_tag() { |
| local tag=$1 |
| shift |
| if [ $# -ne 0 ]; then |
| echo "${indent}<${tag}" |
| indent_push |
| tag_attributes "$@" |
| echo "${indent}>" |
| else |
| echo "${indent}<${tag}>" |
| indent_push |
| fi |
| } |
| |
| close_tag() { |
| local tag=$1 |
| indent_pop |
| echo "${indent}</${tag}>" |
| } |
| |
| tag() { |
| local tag=$1 |
| shift |
| if [ $# -ne 0 ]; then |
| echo "${indent}<${tag}" |
| indent_push |
| tag_attributes "$@" |
| indent_pop |
| echo "${indent}/>" |
| else |
| echo "${indent}<${tag}/>" |
| fi |
| } |
| |
| tag_content() { |
| local tag=$1 |
| local content=$2 |
| shift |
| shift |
| if [ $# -ne 0 ]; then |
| echo "${indent}<${tag}" |
| indent_push |
| tag_attributes "$@" |
| echo "${indent}>${content}</${tag}>" |
| indent_pop |
| else |
| echo "${indent}<${tag}>${content}</${tag}>" |
| fi |
| } |
| |
| generate_filter() { |
| local name=$1 |
| local pats=$2 |
| local file_list_sz |
| local i |
| local f |
| local saveIFS="$IFS" |
| local pack |
| echo "generating filter '$name' from ${#file_list[@]} files" >&2 |
| IFS=* |
| |
| file_list_sz=${#file_list[@]} |
| for i in ${!file_list[@]}; do |
| f=${file_list[i]} |
| for pat in ${pats//;/$IFS}; do |
| if [ "${f##*.}" == "$pat" ]; then |
| unset file_list[i] |
| |
| objf=$(echo ${f%.*}.obj | sed -e 's/^[\./]\+//g' -e 's,/,_,g') |
| |
| if ([ "$pat" == "asm" ] || [ "$pat" == "s" ]) && $asm_use_custom_step; then |
| open_tag CustomBuild \ |
| Include=".\\$f" |
| for plat in "${platforms[@]}"; do |
| for cfg in Debug Release; do |
| tag_content Message "Assembling %(Filename)%(Extension)" \ |
| Condition="'\$(Configuration)|\$(Platform)'=='$cfg|$plat'" |
| tag_content Command "$(eval echo \$asm_${cfg}_cmdline) -o \$(IntDir)$objf" \ |
| Condition="'\$(Configuration)|\$(Platform)'=='$cfg|$plat'" |
| tag_content Outputs "\$(IntDir)$objf" \ |
| Condition="'\$(Configuration)|\$(Platform)'=='$cfg|$plat'" |
| done |
| done |
| close_tag CustomBuild |
| elif [ "$pat" == "c" ] || [ "$pat" == "cc" ] ; then |
| open_tag ClCompile \ |
| Include=".\\$f" |
| # Separate file names with Condition? |
| tag_content ObjectFileName "\$(IntDir)$objf" |
| close_tag ClCompile |
| elif [ "$pat" == "h" ] ; then |
| tag ClInclude \ |
| Include=".\\$f" |
| elif [ "$pat" == "vcxproj" ] ; then |
| open_tag ProjectReference \ |
| Include="$f" |
| depguid=`grep ProjectGuid "$f" | sed 's,.*<.*>\(.*\)</.*>.*,\1,'` |
| tag_content Project "$depguid" |
| tag_content ReferenceOutputAssembly false |
| close_tag ProjectReference |
| else |
| tag None \ |
| Include=".\\$f" |
| fi |
| |
| break |
| fi |
| done |
| done |
| |
| IFS="$saveIFS" |
| } |
| |
| # Process command line |
| unset target |
| for opt in "$@"; do |
| optval="${opt#*=}" |
| case "$opt" in |
| --help|-h) show_help |
| ;; |
| --target=*) target="${optval}" |
| ;; |
| --out=*) outfile="$optval" |
| ;; |
| --name=*) name="${optval}" |
| ;; |
| --proj-guid=*) guid="${optval}" |
| ;; |
| --module-def=*) module_def="${optval}" |
| ;; |
| --exe) proj_kind="exe" |
| ;; |
| --dll) proj_kind="dll" |
| ;; |
| --lib) proj_kind="lib" |
| ;; |
| --src-path-bare=*) src_path_bare="$optval" |
| ;; |
| --static-crt) use_static_runtime=true |
| ;; |
| --ver=*) |
| vs_ver="$optval" |
| case "$optval" in |
| 10|11|12) |
| ;; |
| *) die Unrecognized Visual Studio Version in $opt |
| ;; |
| esac |
| ;; |
| -I*) |
| opt="${opt%/}" |
| incs="${incs}${incs:+;}${opt##-I}" |
| yasmincs="${yasmincs} ${opt}" |
| ;; |
| -D*) defines="${defines}${defines:+;}${opt##-D}" |
| ;; |
| -L*) # fudge . to $(OutDir) |
| if [ "${opt##-L}" == "." ]; then |
| libdirs="${libdirs}${libdirs:+;}\$(OutDir)" |
| else |
| # Also try directories for this platform/configuration |
| libdirs="${libdirs}${libdirs:+;}${opt##-L}" |
| libdirs="${libdirs}${libdirs:+;}${opt##-L}/\$(PlatformName)/\$(Configuration)" |
| libdirs="${libdirs}${libdirs:+;}${opt##-L}/\$(PlatformName)" |
| fi |
| ;; |
| -l*) libs="${libs}${libs:+ }${opt##-l}.lib" |
| ;; |
| -*) die_unknown $opt |
| ;; |
| *) |
| file_list[${#file_list[@]}]="$opt" |
| case "$opt" in |
| *.asm|*.s) uses_asm=true |
| ;; |
| esac |
| ;; |
| esac |
| done |
| outfile=${outfile:-/dev/stdout} |
| guid=${guid:-`generate_uuid`} |
| asm_use_custom_step=false |
| uses_asm=${uses_asm:-false} |
| case "${vs_ver:-11}" in |
| 10|11|12) |
| asm_use_custom_step=$uses_asm |
| ;; |
| esac |
| |
| [ -n "$name" ] || die "Project name (--name) must be specified!" |
| [ -n "$target" ] || die "Target (--target) must be specified!" |
| |
| if ${use_static_runtime:-false}; then |
| release_runtime=MultiThreaded |
| debug_runtime=MultiThreadedDebug |
| lib_sfx=mt |
| else |
| release_runtime=MultiThreadedDLL |
| debug_runtime=MultiThreadedDebugDLL |
| lib_sfx=md |
| fi |
| |
| # Calculate debug lib names: If a lib ends in ${lib_sfx}.lib, then rename |
| # it to ${lib_sfx}d.lib. This precludes linking to release libs from a |
| # debug exe, so this may need to be refactored later. |
| for lib in ${libs}; do |
| if [ "$lib" != "${lib%${lib_sfx}.lib}" ]; then |
| lib=${lib%.lib}d.lib |
| fi |
| debug_libs="${debug_libs}${debug_libs:+ }${lib}" |
| done |
| debug_libs=${debug_libs// /;} |
| libs=${libs// /;} |
| |
| |
| # List of all platforms supported for this target |
| case "$target" in |
| x86_64*) |
| platforms[0]="x64" |
| asm_Debug_cmdline="yasm -Xvc -g cv8 -f \$(PlatformName) ${yasmincs} "%(FullPath)"" |
| asm_Release_cmdline="yasm -Xvc -f \$(PlatformName) ${yasmincs} "%(FullPath)"" |
| ;; |
| x86*) |
| platforms[0]="Win32" |
| asm_Debug_cmdline="yasm -Xvc -g cv8 -f \$(PlatformName) ${yasmincs} "%(FullPath)"" |
| asm_Release_cmdline="yasm -Xvc -f \$(PlatformName) ${yasmincs} "%(FullPath)"" |
| ;; |
| arm*) |
| asm_Debug_cmdline="armasm -nologo "%(FullPath)"" |
| asm_Release_cmdline="armasm -nologo "%(FullPath)"" |
| if [ "$name" = "obj_int_extract" ]; then |
| # We don't want to build this tool for the target architecture, |
| # but for an architecture we can run locally during the build. |
| platforms[0]="Win32" |
| else |
| platforms[0]="ARM" |
| fi |
| ;; |
| *) die "Unsupported target $target!" |
| ;; |
| esac |
| |
| generate_vcxproj() { |
| echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>" |
| open_tag Project \ |
| DefaultTargets="Build" \ |
| ToolsVersion="4.0" \ |
| xmlns="http://schemas.microsoft.com/developer/msbuild/2003" \ |
| |
| open_tag ItemGroup \ |
| Label="ProjectConfigurations" |
| for plat in "${platforms[@]}"; do |
| for config in Debug Release; do |
| open_tag ProjectConfiguration \ |
| Include="$config|$plat" |
| tag_content Configuration $config |
| tag_content Platform $plat |
| close_tag ProjectConfiguration |
| done |
| done |
| close_tag ItemGroup |
| |
| open_tag PropertyGroup \ |
| Label="Globals" |
| tag_content ProjectGuid "{${guid}}" |
| tag_content RootNamespace ${name} |
| tag_content Keyword ManagedCProj |
| close_tag PropertyGroup |
| |
| tag Import \ |
| Project="\$(VCTargetsPath)\\Microsoft.Cpp.Default.props" |
| |
| for plat in "${platforms[@]}"; do |
| for config in Release Debug; do |
| open_tag PropertyGroup \ |
| Condition="'\$(Configuration)|\$(Platform)'=='$config|$plat'" \ |
| Label="Configuration" |
| if [ "$proj_kind" = "exe" ]; then |
| tag_content ConfigurationType Application |
| elif [ "$proj_kind" = "dll" ]; then |
| tag_content ConfigurationType DynamicLibrary |
| else |
| tag_content ConfigurationType StaticLibrary |
| fi |
| if [ "$vs_ver" = "11" ]; then |
| if [ "$plat" = "ARM" ]; then |
| # Setting the wp80 toolchain automatically sets the |
| # WINAPI_FAMILY define, which is required for building |
| # code for arm with the windows headers. Alternatively, |
| # one could add AppContainerApplication=true in the Globals |
| # section and add PrecompiledHeader=NotUsing and |
| # CompileAsWinRT=false in ClCompile and SubSystem=Console |
| # in Link. |
| tag_content PlatformToolset v110_wp80 |
| else |
| tag_content PlatformToolset v110 |
| fi |
| fi |
| if [ "$vs_ver" = "12" ]; then |
| if [ "$plat" = "ARM" ]; then |
| # Setting the wp80 toolchain automatically sets the |
| # WINAPI_FAMILY define, which is required for building |
| # code for arm with the windows headers. Alternatively, |
| # one could add AppContainerApplication=true in the Globals |
| # section and add PrecompiledHeader=NotUsing and |
| # CompileAsWinRT=false in ClCompile and SubSystem=Console |
| # in Link. |
| tag_content PlatformToolset v120_wp80 |
| else |
| tag_content PlatformToolset v120 |
| fi |
| fi |
| tag_content CharacterSet Unicode |
| if [ "$config" = "Release" ]; then |
| tag_content WholeProgramOptimization true |
| fi |
| close_tag PropertyGroup |
| done |
| done |
| |
| tag Import \ |
| Project="\$(VCTargetsPath)\\Microsoft.Cpp.props" |
| |
| open_tag ImportGroup \ |
| Label="PropertySheets" |
| tag Import \ |
| Project="\$(UserRootDir)\\Microsoft.Cpp.\$(Platform).user.props" \ |
| Condition="exists('\$(UserRootDir)\\Microsoft.Cpp.\$(Platform).user.props')" \ |
| Label="LocalAppDataPlatform" |
| close_tag ImportGroup |
| |
| tag PropertyGroup \ |
| Label="UserMacros" |
| |
| for plat in "${platforms[@]}"; do |
| plat_no_ws=`echo $plat | sed 's/[^A-Za-z0-9_]/_/g'` |
| for config in Debug Release; do |
| open_tag PropertyGroup \ |
| Condition="'\$(Configuration)|\$(Platform)'=='$config|$plat'" |
| tag_content OutDir "\$(SolutionDir)$plat_no_ws\\\$(Configuration)\\" |
| tag_content IntDir "$plat_no_ws\\\$(Configuration)\\${name}\\" |
| close_tag PropertyGroup |
| done |
| done |
| |
| for plat in "${platforms[@]}"; do |
| for config in Debug Release; do |
| open_tag ItemDefinitionGroup \ |
| Condition="'\$(Configuration)|\$(Platform)'=='$config|$plat'" |
| if [ "$name" = "vpx" ]; then |
| open_tag PreBuildEvent |
| tag_content Command "call obj_int_extract.bat $src_path_bare" |
| close_tag PreBuildEvent |
| fi |
| open_tag ClCompile |
| if [ "$config" = "Debug" ]; then |
| opt=Disabled |
| runtime=$debug_runtime |
| curlibs=$debug_libs |
| confsuffix=d |
| case "$name" in |
| obj_int_extract) |
| debug=DEBUG |
| ;; |
| *) |
| debug=_DEBUG |
| ;; |
| esac |
| else |
| opt=MaxSpeed |
| runtime=$release_runtime |
| curlibs=$libs |
| confsuffix="" |
| tag_content FavorSizeOrSpeed Speed |
| debug=NDEBUG |
| fi |
| case "$name" in |
| obj_int_extract) |
| extradefines=";_CONSOLE" |
| ;; |
| *) |
| extradefines=";$defines" |
| ;; |
| esac |
| tag_content Optimization $opt |
| tag_content AdditionalIncludeDirectories "$incs;%(AdditionalIncludeDirectories)" |
| tag_content PreprocessorDefinitions "WIN32;$debug;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE$extradefines;%(PreprocessorDefinitions)" |
| tag_content RuntimeLibrary $runtime |
| tag_content WarningLevel Level3 |
| # DebugInformationFormat |
| close_tag ClCompile |
| case "$proj_kind" in |
| exe) |
| open_tag Link |
| if [ "$name" = "obj_int_extract" ]; then |
| tag_content OutputFile "${name}.exe" |
| else |
| tag_content AdditionalDependencies "$curlibs" |
| tag_content AdditionalLibraryDirectories "$libdirs;%(AdditionalLibraryDirectories)" |
| fi |
| tag_content GenerateDebugInformation true |
| close_tag Link |
| ;; |
| dll) |
| open_tag Link |
| tag_content GenerateDebugInformation true |
| tag_content ModuleDefinitionFile $module_def |
| close_tag Link |
| ;; |
| lib) |
| open_tag Lib |
| tag_content OutputFile "\$(OutDir)${name}${lib_sfx}${confsuffix}.lib" |
| close_tag Lib |
| ;; |
| esac |
| close_tag ItemDefinitionGroup |
| done |
| |
| done |
| |
| open_tag ItemGroup |
| generate_filter "Source Files" "c;cc;def;odl;idl;hpj;bat;asm;asmx;s" |
| close_tag ItemGroup |
| open_tag ItemGroup |
| generate_filter "Header Files" "h;hm;inl;inc;xsd" |
| close_tag ItemGroup |
| open_tag ItemGroup |
| generate_filter "Build Files" "mk" |
| close_tag ItemGroup |
| open_tag ItemGroup |
| generate_filter "References" "vcxproj" |
| close_tag ItemGroup |
| |
| tag Import \ |
| Project="\$(VCTargetsPath)\\Microsoft.Cpp.targets" |
| |
| open_tag ImportGroup \ |
| Label="ExtensionTargets" |
| close_tag ImportGroup |
| |
| close_tag Project |
| |
| # This must be done from within the {} subshell |
| echo "Ignored files list (${#file_list[@]} items) is:" >&2 |
| for f in "${file_list[@]}"; do |
| echo " $f" >&2 |
| done |
| } |
| |
| # This regexp doesn't catch most of the strings in the vcxproj format, |
| # since they're like <tag>path</tag> instead of <tag attr="path" /> |
| # as previously. It still seems to work ok despite this. |
| generate_vcxproj | |
| sed -e '/"/s;\([^ "]\)/;\1\\;g' | |
| sed -e '/xmlns/s;\\;/;g' > ${outfile} |
| |
| exit |