VS10: Finish Midl support (#11461)

This commit addresses all of the following:
  http://public.kitware.com/Bug/view.php?id=8165
  http://public.kitware.com/Bug/view.php?id=10687
  http://public.kitware.com/Bug/view.php?id=11311
  http://public.kitware.com/Bug/view.php?id=11461

With this commit, the midl support for VS10 is as
complete as midl support ever was for VS9 and earlier.
The VSMidl test should run on all Visual Studio
generator based dashboards.

CMake no longer sends C++ compiler /D flag values
to the midl compiler in Visual Studio generated
projects. I think if we want to add that in the
future, we should add a way to pass midl compiler
specific flags and perhaps an optional way to add
in the C++ definitions, too. For now, not sending
them along gets past the immediate problem wherein
idl files in a CMake VS generated project just didn't
work at all.

The VSMidl test added in this commit was inspired by
the patch attached to 8165.

The test had to be modified such that it will run in
a directory whose name contains no spaces. There is an
existing bug filed against VS10's midl asking Microsoft
to fix that problem. But for now, the test added in this
commit works by copying the source directory to a location
that avoids spaces in the directory names.

Inspired-By: Robert Lenhardt
This commit is contained in:
David Cole 2011-01-04 18:51:15 -05:00
parent c59ed29552
commit 13caaa3eb7
7 changed files with 164 additions and 4 deletions

View File

@ -797,7 +797,6 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout,
tool = "VFMIDLTool"; tool = "VFMIDLTool";
} }
fout << "\t\t\t<Tool\n\t\t\t\tName=\"" << tool << "\"\n"; fout << "\t\t\t<Tool\n\t\t\t\tName=\"" << tool << "\"\n";
targetOptions.OutputPreprocessorDefinitions(fout, "\t\t\t\t", "\n");
fout << "\t\t\t\tMkTypLibCompatible=\"FALSE\"\n"; fout << "\t\t\t\tMkTypLibCompatible=\"FALSE\"\n";
if( this->PlatformName == "x64" ) if( this->PlatformName == "x64" )
{ {

View File

@ -436,6 +436,7 @@ void cmVisualStudio10TargetGenerator::WriteGroups()
std::vector<cmSourceFile*> customBuild; std::vector<cmSourceFile*> customBuild;
std::vector<cmSourceFile*> none; std::vector<cmSourceFile*> none;
std::vector<cmSourceFile*> headers; std::vector<cmSourceFile*> headers;
std::vector<cmSourceFile*> idls;
std::vector<cmSourceFile*> resource; std::vector<cmSourceFile*> resource;
for(std::vector<cmSourceFile*>::const_iterator s = classes.begin(); for(std::vector<cmSourceFile*>::const_iterator s = classes.begin();
@ -458,7 +459,7 @@ void cmVisualStudio10TargetGenerator::WriteGroups()
{ {
clCompile.push_back(sf); clCompile.push_back(sf);
} }
if(strcmp(lang, "RC") == 0) else if(strcmp(lang, "RC") == 0)
{ {
resource.push_back(sf); resource.push_back(sf);
} }
@ -470,6 +471,10 @@ void cmVisualStudio10TargetGenerator::WriteGroups()
{ {
headers.push_back(sf); headers.push_back(sf);
} }
else if(sf->GetExtension() == "idl")
{
idls.push_back(sf);
}
else else
{ {
none.push_back(sf); none.push_back(sf);
@ -498,6 +503,7 @@ void cmVisualStudio10TargetGenerator::WriteGroups()
this->WriteGroupSources("ClCompile", clCompile, sourceGroups); this->WriteGroupSources("ClCompile", clCompile, sourceGroups);
this->WriteGroupSources("ClInclude", headers, sourceGroups); this->WriteGroupSources("ClInclude", headers, sourceGroups);
this->WriteGroupSources("ResourceCompile", resource, sourceGroups); this->WriteGroupSources("ResourceCompile", resource, sourceGroups);
this->WriteGroupSources("Midl", idls, sourceGroups);
this->WriteGroupSources("CustomBuild", customBuild, sourceGroups); this->WriteGroupSources("CustomBuild", customBuild, sourceGroups);
this->WriteString("<ItemGroup>\n", 1); this->WriteString("<ItemGroup>\n", 1);
@ -670,6 +676,7 @@ void cmVisualStudio10TargetGenerator::WriteCLSources()
const char* lang = (*source)->GetLanguage(); const char* lang = (*source)->GetLanguage();
bool cl = lang && (strcmp(lang, "C") == 0 || strcmp(lang, "CXX") ==0); bool cl = lang && (strcmp(lang, "C") == 0 || strcmp(lang, "CXX") ==0);
bool rc = lang && (strcmp(lang, "RC") == 0); bool rc = lang && (strcmp(lang, "RC") == 0);
bool idl = (*source)->GetExtension() == "idl";
std::string sourceFile = (*source)->GetFullPath(); std::string sourceFile = (*source)->GetFullPath();
sourceFile = cmSystemTools::RelativePath( sourceFile = cmSystemTools::RelativePath(
this->Makefile->GetCurrentOutputDirectory(), this->Makefile->GetCurrentOutputDirectory(),
@ -688,6 +695,10 @@ void cmVisualStudio10TargetGenerator::WriteCLSources()
{ {
this->WriteString("<ResourceCompile Include=\"", 2); this->WriteString("<ResourceCompile Include=\"", 2);
} }
else if(idl)
{
this->WriteString("<Midl Include=\"", 2);
}
else else
{ {
this->WriteString("<None Include=\"", 2); this->WriteString("<None Include=\"", 2);
@ -1394,11 +1405,20 @@ WriteMidlOptions(std::string const& /*config*/,
{ {
this->WriteString("<Midl>\n", 2); this->WriteString("<Midl>\n", 2);
this->OutputIncludes(includes); this->OutputIncludes(includes);
this->WriteString("<OutputDirectory>$(IntDir)</OutputDirectory>\n", 3);
this->WriteString("<HeaderFileName>%(Filename).h</HeaderFileName>\n", 3);
this->WriteString(
"<TypeLibraryName>%(Filename).tlb</TypeLibraryName>\n", 3);
this->WriteString(
"<InterfaceIdentifierFileName>"
"%(Filename)_i.c</InterfaceIdentifierFileName>\n", 3);
this->WriteString("<ProxyFileName>%(Filename)_p.c</ProxyFileName>\n",3);
this->WriteString("</Midl>\n", 2); this->WriteString("</Midl>\n", 2);
} }
void cmVisualStudio10TargetGenerator::WriteItemDefinitionGroups() void cmVisualStudio10TargetGenerator::WriteItemDefinitionGroups()
{ {
std::vector<std::string> *configs = std::vector<std::string> *configs =
static_cast<cmGlobalVisualStudio7Generator *> static_cast<cmGlobalVisualStudio7Generator *>
(this->GlobalGenerator)->GetConfigurations(); (this->GlobalGenerator)->GetConfigurations();

View File

@ -1075,6 +1075,17 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/
--build-makeprogram ${CMAKE_TEST_MAKEPROGRAM} --build-makeprogram ${CMAKE_TEST_MAKEPROGRAM}
--test-command VSExternalInclude) --test-command VSExternalInclude)
LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/VSExternalInclude") LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/VSExternalInclude")
ADD_TEST(VSMidl ${CMAKE_CTEST_COMMAND}
--build-and-test
"${CMake_SOURCE_DIR}/Tests/VSMidl"
"${CMake_BINARY_DIR}/Tests/VSMidl"
--build-two-config
--build-generator ${CMAKE_TEST_GENERATOR}
--build-project VSMidl
--build-makeprogram ${CMAKE_TEST_MAKEPROGRAM}
--test-command VSMidl)
LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/VSMidl")
ENDIF(${CMAKE_TEST_GENERATOR} MATCHES "Visual Studio") ENDIF(${CMAKE_TEST_GENERATOR} MATCHES "Visual Studio")
IF (APPLE AND CMAKE_COMPILER_IS_GNUCXX) IF (APPLE AND CMAKE_COMPILER_IS_GNUCXX)

View File

@ -0,0 +1,78 @@
# This CMakeLists.txt file exists solely to drive the one found in the "src"
# subdir as an ExternalProject build. The project in "src" cannot build when
# there is a space in the directory name, so we copy that directory to a place
# guaranteed not to have a space in the name, build it there, and then copy the
# resulting output directory back up here into this CMake test's build tree.
#
if(NOT DEFINED CMAKE_BUILDNAME)
string(REGEX REPLACE "^.*/([^/]+)/[^/]+/([^/]+)$" "\\1" CMAKE_BUILDNAME "${CMAKE_CURRENT_BINARY_DIR}")
string(REGEX REPLACE "^.*/([^/]+)/[^/]+/([^/]+)$" "\\2" THIS_TESTNAME "${CMAKE_CURRENT_BINARY_DIR}")
string(REPLACE " " "_" CMAKE_BUILDNAME "${CMAKE_BUILDNAME}")
endif()
message(STATUS "CMAKE_BUILDNAME='${CMAKE_BUILDNAME}'")
message(STATUS "THIS_TESTNAME='${THIS_TESTNAME}'")
cmake_minimum_required(VERSION 2.8)
project(${THIS_TESTNAME})
include(ExternalProject)
if(NOT DEFINED HOME)
if(DEFINED ENV{CTEST_REAL_HOME})
set(HOME "$ENV{CTEST_REAL_HOME}")
else()
set(HOME "$ENV{HOME}")
endif()
if(NOT HOME AND WIN32)
# Try for USERPROFILE as HOME equivalent:
string(REPLACE "\\" "/" HOME "$ENV{USERPROFILE}")
# But just use root of SystemDrive if USERPROFILE contains any spaces:
# (Default on XP and earlier...)
if(HOME MATCHES " ")
string(REPLACE "\\" "/" HOME "$ENV{SystemDrive}")
endif()
endif()
endif()
message(STATUS "HOME='${HOME}'")
if(NOT DEFINED url)
set(url "${CMAKE_CURRENT_SOURCE_DIR}/src")
endif()
message(STATUS "url='${url}'")
set(base_dir "${HOME}/.cmake/Dashboards/${CMAKE_BUILDNAME}/${THIS_TESTNAME}")
set(binary_dir "${base_dir}/build")
set(source_dir "${base_dir}/src")
# Source dir for this project exists in the CMake source tree, but we cannot
# use it in-place since there might be a space in its directory name.
# Source dir is therefore copied under a '.cmake/Dashboards'
# dir in your HOME directory to give it a name with no spaces.
#
ExternalProject_Add(clean-${PROJECT_NAME}
DOWNLOAD_COMMAND ""
CONFIGURE_COMMAND ${CMAKE_COMMAND} -E remove_directory "${source_dir}"
BUILD_COMMAND ${CMAKE_COMMAND} -E remove_directory "${binary_dir}"
INSTALL_COMMAND ""
)
ExternalProject_Add(download-${PROJECT_NAME}
URL "${url}"
SOURCE_DIR "${source_dir}"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
DEPENDS clean-${PROJECT_NAME}
)
ExternalProject_Add(build-${PROJECT_NAME}
DOWNLOAD_COMMAND ""
SOURCE_DIR "${source_dir}"
BINARY_DIR "${binary_dir}"
INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory
"${binary_dir}/${CMAKE_CFG_INTDIR}"
"${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}"
DEPENDS download-${PROJECT_NAME}
)

View File

@ -0,0 +1,5 @@
cmake_minimum_required(VERSION 2.8)
project(VSMidl)
include_directories("${CMAKE_CURRENT_BINARY_DIR}/\$(IntDir)")
add_executable(VSMidl main.cpp test.idl)

17
Tests/VSMidl/src/main.cpp Normal file
View File

@ -0,0 +1,17 @@
#include <stdio.h>
#include <test.h>
#include <test_i.c>
int main(int argc, char** argv)
{
IID libid = LIBID_CMakeMidlTestLib;
CLSID clsid = CLSID_CMakeMidlTest;
IID iid = IID_ICMakeMidlTest;
printf("Running '%s'\n", argv[0]);
printf(" libid starts with '0x%08lx'\n", (long) libid.Data1);
printf(" clsid starts with '0x%08lx'\n", (long) clsid.Data1);
printf(" iid starts with '0x%08lx'\n", (long) iid.Data1);
return 0;
}

30
Tests/VSMidl/src/test.idl Normal file
View File

@ -0,0 +1,30 @@
import "oaidl.idl";
import "ocidl.idl";
[
object,
uuid(258CCEBE-8EE4-4A48-B78C-AC53BCD59E28),
dual,
nonextensible,
helpstring("ICMakeTest Interface"),
pointer_default(unique)
]
interface ICMakeMidlTest : IUnknown
{
[id(1), helpstring("method Method")] HRESULT Method();
}
[
uuid(0537BA59-7EEC-48F8-BD4B-369BC7D9807E),
]
library CMakeMidlTestLib
{
[
uuid(D2A90807-019A-46E5-BF47-FF4FA4352D2A),
helpstring("CMakeMidlTest Class")
]
coclass CMakeMidlTest
{
[default] interface ICMakeMidlTest;
};
}