summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt18
-rw-r--r--apps/samples/map/spoken-map-ticker.scxml2
-rw-r--r--apps/samples/miles/miles.js664
-rw-r--r--apps/samples/vrml/vrml-server.scxml2
-rw-r--r--apps/uscxml-browser.cpp146
-rw-r--r--config.h.in2
-rw-r--r--contrib/cmake/FindEVENT.cmake27
-rw-r--r--contrib/cmake/USCXMLMacros.cmake1
-rw-r--r--contrib/cmake/cotire.cmake3239
-rw-r--r--contrib/src/getopt/getopt.c562
-rw-r--r--contrib/src/getopt/getopt.h95
-rw-r--r--src/bindings/swig/php/uscxmlNativePHP.php68
-rw-r--r--src/uscxml/Interpreter.cpp167
-rw-r--r--src/uscxml/Interpreter.h47
-rw-r--r--src/uscxml/concurrency/eventqueue/DelayedEventQueue.cpp12
-rw-r--r--src/uscxml/concurrency/eventqueue/DelayedEventQueue.h6
-rw-r--r--src/uscxml/pch.h14
-rw-r--r--src/uscxml/plugins/datamodel/CMakeLists.txt106
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/TypedArray.h1
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/v8/V8DOM.h1
-rw-r--r--src/uscxml/plugins/invoker/im/IMInvoker.cpp412
-rw-r--r--src/uscxml/plugins/invoker/im/IMInvoker.h46
-rw-r--r--src/uscxml/server/HTTPServer.cpp162
-rw-r--r--src/uscxml/server/HTTPServer.h21
-rw-r--r--test/CMakeLists.txt11
-rw-r--r--test/samples/uscxml/test-instant-messaging.scxml17
-rw-r--r--test/samples/uscxml/test-performance.scxml2
-rw-r--r--test/samples/uscxml/test-startup-time.scxml4
-rw-r--r--test/src/test-arabica-events.cpp2
-rw-r--r--test/src/test-arabica-parsing.cpp2
-rw-r--r--test/src/test-arabica-xpath.cpp2
-rw-r--r--test/src/test-cmdline-parsing.cpp109
-rw-r--r--test/src/test-instant-messaging.cpp298
33 files changed, 5928 insertions, 340 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2921af0..dfd0a38 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -493,6 +493,7 @@ include_directories(${Boost_INCLUDE_DIR})
find_package(EVENT REQUIRED)
include_directories(${EVENT_INCLUDE_DIR})
list (APPEND USCXML_CORE_LIBS ${EVENT_LIBRARY})
+#set(EVENT_SSL_FOUND OFF) # deactivate for now
#################################################
# Optional libraries
@@ -527,6 +528,13 @@ else()
endif()
+find_package(OpenSSL)
+if (OPENSSL_FOUND)
+ include_directories(${OPENSSL_INCLUDE_DIR})
+ list (APPEND USCXML_OPT_LIBS ${OPENSSL_LIBRARIES})
+endif()
+
+
set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_SHARED})
find_package(SWI)
if (SWI_FOUND)
@@ -729,6 +737,12 @@ foreach( FILE ${USCXML_FILES} )
endif()
endforeach()
+# add compile time reducer
+# see https://github.com/sakra/cotire
+if ((WIN32 OR UNIX) AND NOT APPLE)
+ include(cotire)
+endif()
+
# build library
if (BUILD_AS_PLUGINS)
add_library(uscxml ${USCXML_FILES})
@@ -737,6 +751,10 @@ else()
add_library(uscxml ${USCXML_FILES})
target_link_libraries(uscxml ${USCXML_OPT_LIBS} ${USCXML_CORE_LIBS})
endif()
+if ((WIN32 OR UNIX) AND NOT APPLE)
+ set_target_properties(uscxml PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "src/uscxml/pch.h")
+ cotire(uscxml)
+endif()
if (NOT CMAKE_CROSSCOMPILING)
add_executable(uscxml-browser apps/uscxml-browser.cpp ${PROJECT_SOURCE_DIR}/contrib/src/getopt/XGetopt.cpp)
diff --git a/apps/samples/map/spoken-map-ticker.scxml b/apps/samples/map/spoken-map-ticker.scxml
index 147f890..3955715 100644
--- a/apps/samples/map/spoken-map-ticker.scxml
+++ b/apps/samples/map/spoken-map-ticker.scxml
@@ -27,7 +27,7 @@
<invoke type="umundo" id="umundo">
<param name="channel" expr="'map/tick'" />
<finalize>
- <script>dump(_event);</script>
+ <!-- <script>dump(_event);</script> -->
</finalize>
</invoke>
diff --git a/apps/samples/miles/miles.js b/apps/samples/miles/miles.js
new file mode 100644
index 0000000..a3cdcae
--- /dev/null
+++ b/apps/samples/miles/miles.js
@@ -0,0 +1,664 @@
+function Miles(element, params) {
+
+ // private attributes
+ var self = this;
+
+ // private instanceId
+ if (!Miles.instances)
+ Miles.instances = 0;
+ this.instanceId = Miles.instances++;
+
+ // public attributes
+ this.reflectorURL = "127.0.0.1";
+ this.params = params;
+
+ // privileged public methods
+ this.foo = function() {
+ };
+
+ // privileged private methods
+ var bar = function(param1, param2) {
+ };
+
+ // start of actual class after we fetched all dojo thingies
+ require(["dojo/dom-construct",
+ "dojo/_base/xhr",
+ "dojo/dom",
+ "dojo/on",
+ "dojox/storage",
+ "dojo/store/Memory",
+ "dojo/store/Observable",
+ "dijit/tree/ObjectStoreModel",
+ "dijit/Tree",
+ "dijit/form/TextBox",
+ "dijit/form/Button",
+ "dojox/widget/Standby",
+ "dijit/form/DropDownButton",
+ "dijit/TooltipDialog",
+ "dojo/dnd/Moveable",
+ "dojo/ready",
+ "dojo/dnd/Source",
+ "dijit/form/HorizontalSlider",
+ "dijit/form/Select",
+ "dijit/form/NumberSpinner"],
+ function(domConst,
+ xhr,
+ dom,
+ on,
+ storage,
+ Memory,
+ Observable,
+ ObjectStoreModel,
+ Tree,
+ TextBox,
+ Button,
+ Standby,
+ DropDownButton,
+ TooltipDialog,
+ Moveable,
+ ready,
+ Source,
+ HorizontalSlider,
+ Selector,
+ NumberSpinner) {
+
+ ready(function() {
+
+ if (typeof(element) === 'string') {
+ element = dom.byId(element);
+ }
+
+ self.element = element;
+ self.xhr = xhr;
+ self.localStorage = dojox.storage.manager.getProvider();
+ self.localStorage.initialize();
+
+ // establish our dom
+ element.appendChild(domConst.toDom('\
+ <table>\
+ <tr>\
+ <td valign="top">\
+ <div style="position: relative; padding: 0px">\
+ <img class="model" src="' + self.resRoot + 'img/Tutorial.png" style="z-index: -1; width: ' + self.pose.width + 'px; height: ' + self.pose.height + 'px"></img>\
+ <div style="z-index: 1; position: absolute; right: 45%; top: 45%">\
+ <div class="progress"></div>\
+ </div>\
+ <div style="position: absolute; left: 10px; top: 10px">\
+ <table></tr>\
+ <td class="filesDropDown" style="vertical-align: middle"></td>\
+ <td>\
+ <div class="movieDropDown" style="display: inline"></div>\
+ <button type="button" class="movieAddButton"></button>\
+ </td>\
+ <td align="right"><button type="button" class="resetButton"></button></td>\
+ <td class="dragHandler" style="vertical-align: middle; padding-top: 4px;"></td>\
+ </tr></table>\
+ </div>\
+ <div style="position: absolute; right: 10px; top: 15%; height: 50%">\
+ <div class="zoomSlide"></div>\
+ </div>\
+ <div style="position: absolute; right: 50%; top: 50%">\
+ <div class="pitchRollHandler" style="font-size: 0.5em; background-color: rgba(255,255,255,0.5); border-radius: 5px; moz-border-radius: 5px;">\
+ <table>\
+ <tr>\
+ <td><img class="pitchRollHandlerImg" src="' + self.resRoot + 'img/pitchRoll-handle.png" height="20px" style="padding: 2px 0px 0px 4px;" /></td>\
+ <td><div class="pitchLabel"></div><div class="rollLabel"></div></td>\
+ </tr>\
+ </table>\
+ </div>\
+ </div>\
+ <div style="position: absolute; right: 50%; top: 50%">\
+ <div class="yawZoomHandler">\
+ <div style="font-size: 0.5em; background-color: rgba(255,255,255,0.5); border-radius: 5px; moz-border-radius: 5px; position: absolute; left: -34px;">\
+ <table>\
+ <tr>\
+ <td><img class="yawZoomHandlerImg" src="' + self.resRoot + 'img/yawZoom-handle.png" height="20px" style="padding: 2px 0px 0px 4px;" /></td>\
+ <td><div class="yawLabel"></div><div class="zoomLabel"></div></td>\
+ </tr>\
+ </table>\
+ </div>\
+ </div>\
+ </div>\
+ <div style="position: absolute; right: 50%; top: 50%">\
+ <div class="xyHandler" style="font-size: 0.5em; background-color: rgba(255,255,255,0.5); border-radius: 5px; moz-border-radius: 5px;">\
+ <table>\
+ <tr>\
+ <td><img class="xyHandlerImg" src="' + self.resRoot + 'img/xy-handle.png" width="20px" style="padding: 2px 0px 0px 4px;" /></td>\
+ <td><div class="xLabel"></div><div class="yLabel"></div></td>\
+ </tr>\
+ </table>\
+ </div>\
+ </div>\
+ </div>\
+ </td>\
+ <td valign="top" height="100%">\
+ </td>\
+ </tr>\
+ <tr>\
+ <td colspan="2"><div class="messages"></div></td>\
+ </tr>\
+ </table>\
+ '));
+
+ // fetch special dom nodes for content
+ self.messageBox = dojo.query("div.messages", element)[0];
+ self.imgElem = dojo.query("img.model", element)[0];
+
+ /**
+ * === POSE MANIPULATION AND RESET ====================
+ */
+
+ self.resetButtonElem = dojo.query("button.resetButton", element)[0];
+ self.progressElem = dojo.query("div.progress", element)[0];
+ self.pitchRollHandlerElem = dojo.query(".pitchRollHandler", element)[0];
+ self.yawZoomHandlerElem = dojo.query(".yawZoomHandler", element)[0];
+ self.xyHandlerElem = dojo.query(".xyHandler", element)[0];
+
+ self.pitchRollHandler = new Moveable(self.pitchRollHandlerElem);
+ self.pitchRollHandler.onMoveStop = function(mover) {
+ var handlerImg = dojo.query("img.pitchRollHandlerImg", mover.node)[0];
+ var pitchLabel = dojo.query("div.pitchLabel", mover.node)[0];
+ var rollLabel = dojo.query("div.rollLabel", mover.node)[0];
+
+ pitchLabel.innerHTML = '';
+ rollLabel.innerHTML = '';
+
+ self.updateScene();
+ };
+ self.pitchRollHandler.onMoving = function(mover) {
+ // mover.node.style.backgroundColor = "rgba(255,255,255,0.5)";
+ // mover.node.style.borderRadius = "5px";
+ // mover.node.style.mozBorderRadius = "5px";
+ // mover.node.style.webkitBorderRadius = "5px";
+ var handlerImg = dojo.query(".pitchRollHandlerImg", mover.node)[0];
+ var pitchLabel = dojo.query(".pitchLabel", mover.node)[0];
+ var rollLabel = dojo.query(".rollLabel", mover.node)[0];
+ var offset = moverRelativeTo(handlerImg, self.element);
+
+ offset.x += 30;
+ offset.y += 20;
+
+ self.xyHandlerElem.style.zIndex = 1;
+ self.yawZoomHandlerElem.style.zIndex = 1;
+ self.pitchRollHandlerElem.style.zIndex = 2;
+
+ // self.pose.pitch = self.pose.pitch % (2 * 3.14159);
+ // self.pose.roll = self.pose.roll % (2 * 3.14159);
+ self.pose.roll = offset.x / self.pose.width - 0.5;
+ self.pose.pitch = offset.y / self.pose.height - 0.5;
+ self.pose.pitch *= -1;
+ self.pose.roll *= 2 * 3.14159;
+ self.pose.pitch *= 2 * 3.14159;
+ self.pose.roll = Math.ceil((self.pose.roll) * 10) / 10;
+ self.pose.pitch = Math.ceil((self.pose.pitch) * 10) / 10;
+ pitchLabel.innerHTML = 'Pitch:' + self.pose.pitch;
+ rollLabel.innerHTML = 'Roll:' + self.pose.roll;
+ };
+
+ self.yawZoomHandler = new Moveable(self.yawZoomHandlerElem);
+ self.yawZoomHandler.onMoveStop = function(mover) {
+ var handlerImg = dojo.query("img.yawZoomHandlerImg", mover.node)[0];
+ var yawLabel = dojo.query("div.yawLabel", mover.node)[0];
+ var zoomLabel = dojo.query("div.zoomLabel", mover.node)[0];
+
+ yawLabel.innerHTML = '';
+ zoomLabel.innerHTML = '';
+
+ self.updateScene();
+ };
+ self.yawZoomHandler.onMoving = function(mover) {
+ var handlerImg = dojo.query("img.yawZoomHandlerImg", mover.node)[0];
+ var yawLabel = dojo.query("div.yawLabel", mover.node)[0];
+ var zoomLabel = dojo.query("div.zoomLabel", mover.node)[0];
+ var offset = moverRelativeTo(handlerImg, self.element);
+
+ offset.x += 7;
+ offset.y += 9;
+
+ self.xyHandlerElem.style.zIndex = 1;
+ self.yawZoomHandlerElem.style.zIndex = 2;
+ self.pitchRollHandlerElem.style.zIndex = 1;
+
+ // self.pose.pitch = self.pose.pitch % (2 * 3.14159);
+ // self.pose.roll = self.pose.roll % (2 * 3.14159);
+ self.pose.yaw = (self.pose.width - offset.x) / self.pose.width - 0.5;
+ self.pose.zoom = offset.y / self.pose.height - 0.5;
+ self.pose.yaw *= 2 * 3.14159;
+ self.pose.zoom = self.pose.zoom * 3 + 1;
+ self.pose.zoom = Math.ceil((self.pose.zoom) * 10) / 10;
+ self.pose.yaw = Math.ceil((self.pose.yaw) * 10) / 10;
+ yawLabel.innerHTML = 'Yaw:' + self.pose.yaw;
+ zoomLabel.innerHTML = 'Zoom:' + self.pose.zoom;
+ };
+
+ self.xyHandler = new Moveable(self.xyHandlerElem);
+ self.xyHandler.onMoveStop = function(mover) {
+ var handlerImg = dojo.query("img.xyHandlerImg", mover.node)[0];
+ var xLabel = dojo.query("div.xLabel", mover.node)[0];
+ var yLabel = dojo.query("div.yLabel", mover.node)[0];
+
+ xLabel.innerHTML = '';
+ yLabel.innerHTML = '';
+
+ self.updateScene();
+ };
+ self.xyHandler.onMoving = function(mover) {
+ var handlerImg = dojo.query("img.xyHandlerImg", mover.node)[0];
+ var xLabel = dojo.query("div.xLabel", mover.node)[0];
+ var yLabel = dojo.query("div.yLabel", mover.node)[0];
+ var offset = moverRelativeTo(handlerImg, self.element);
+
+ offset.x += 3;
+ offset.y += 13;
+
+ self.xyHandlerElem.style.zIndex = 2;
+ self.yawZoomHandlerElem.style.zIndex = 1;
+ self.pitchRollHandlerElem.style.zIndex = 1;
+
+ self.pose.x = offset.x / self.pose.width - 0.5;
+ self.pose.y = offset.y / self.pose.height - 0.5;
+ self.pose.x *= 100;
+ self.pose.y *= 100;
+ self.pose.y = Math.ceil((self.pose.y) * 10) / 10;
+ self.pose.x = Math.ceil((self.pose.x) * 10) / 10;
+ xLabel.innerHTML = 'X:' + self.pose.x;
+ yLabel.innerHTML = 'Y:' + self.pose.y;
+ };
+
+ /**
+ * === FILES DROPDOWN ====================
+ */
+
+ self.filesDropDownElem = dojo.query("td.filesDropDown", element)[0];
+
+ self.createAvatar = function(item, mode) {
+ if (mode == 'avatar') {
+ // create your avatar if you want
+ var avatar = dojo.create( 'div', { innerHTML: item.data });
+ var avatarPose = dojo.clone(self.pose);
+ avatarPose.width=60;
+ avatarPose.height=60;
+ var avatarImgUrl = urlSuffixForPose(avatarPose);
+ avatar.innerHTML = '<img src=' + self.imageURL + avatarImgUrl + ' /> ';
+ item.srcEcc = "VRMLViewer";
+ item.iconPoseUrl = self.imageURL + avatarImgUrl;
+ item.imageURL = self.imageURL;
+ item.serverURL = self.serverURL;
+ item.pose = avatarPose;
+ return {node: avatar, data: item, type: item.type};
+ }
+ var handler = dojo.create( 'div', { innerHTML: '<img src="' + self.resRoot + 'img/drag.png" width="20px" />' });
+ return {node: handler, data: item, type: item.type};
+ };
+
+ self.dragHandler = new Source(dojo.query("td.dragHandler", element)[0], {copyOnly: true, creator: self.createAvatar});
+ self.dragHandler.insertNodes(false, [ { } ]);
+
+ // setup fileStore for tree list
+ self.fileStore = new Observable(new Memory({
+ data: [ { id: 'root', name:'3D Models'} ],
+ getChildren: function(object){
+ return this.query({parent: object.id});
+ }
+ }));
+ self.fileTreeModel = new ObjectStoreModel({
+ store: self.fileStore,
+ query: { id: "root" }
+ });
+
+ // setup actual tree dijit
+ self.fileList = new dijit.Tree({
+ id: "fileList" + self.instanceId,
+ model: self.fileTreeModel,
+ persist: false,
+ showRoot: false,
+ style: "height: 300px;",
+ onClick: function(item){
+ if ('url' in item) {
+ self.imageURL = item.url;
+ self.updateScene();
+ }
+ },
+ getIconClass: function(item, opened) {
+ return (!item || !('url' in item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "dijitLeaf";
+ },
+ getIconStyle: function(item, opened){
+ if('url' in item) {
+ return { backgroundImage: "url('" + item.url + "?width=16&height=16')"};
+ }
+ }
+ //return {backgroundImage: "url('" + item.url + "?width=16&height=16')"};
+
+ });
+
+ if (self.params && self.params.serverURL)
+ self.serverURL = self.params.serverURL;
+ var savedServerURL = self.localStorage.get("vrmlServer");
+ if (savedServerURL && !self.serverURL) {
+ self.serverURL = savedServerURL;
+ self.refreshServer(savedServerURL);
+ }
+
+ self.serverBox = new TextBox({
+ name: "Server",
+ value: self.serverURL,
+ style: "width: 65%",
+
+ onKeyUp: function(e) {
+ if (self.browseButton) {
+ if (this.get("value") !== self.serverURL) {
+ self.browseButton.setAttribute('label', 'Browse');
+ } else {
+ self.browseButton.setAttribute('label', 'Refresh');
+ }
+ }
+ },
+
+ onKeyDown: function(e) {
+ var code = e.keyCode || e.which;
+ if( code === 13 ) {
+ e.preventDefault();
+ self.refreshServer(this.get("value"));
+ return false;
+ }
+ },
+ });
+
+ self.browseButton = new Button({
+ label: "Browse",
+ onClick: function(){
+ self.refreshServer(self.serverBox.get("value"));
+ }
+ });
+
+ self.filesDropDownContent = domConst.toDom('<div />');
+ self.filesDropDownContent.appendChild(self.serverBox.domNode);
+ self.filesDropDownContent.appendChild(self.browseButton.domNode);
+ self.filesDropDownContent.appendChild(self.fileList.domNode);
+
+ self.filesToolTip = new TooltipDialog({ content:self.filesDropDownContent, style:"max-height:320px"});
+ self.filesDropDown = new DropDownButton({ label: "Files", dropDown: self.filesToolTip });
+ self.filesDropDownElem.appendChild(self.filesDropDown.domNode);
+
+ self.fileStandby = new Standby({target: self.filesDropDownContent });
+ self.filesDropDownContent.appendChild(self.fileStandby.domNode);
+
+ /**
+ * === MOVIE DROPDOWN ====================
+ */
+
+ self.movieDropDownElem = dojo.query("div.movieDropDown", element)[0];
+ self.movieAddButtonElem = dojo.query("button.movieAddButton", element)[0];
+
+ self.movieDropDownContent = domConst.toDom(
+ '<div style="overflow: auto; max-height: 420px;"> \
+ <table><tr class="movieFormatLengthRow" /></tr><tr class="movieWidthHeightLengthRow" /></table> \
+ <div class=\"dndArea\" /> \
+ </div>'
+ );
+
+ self.movieFormatLengthRowElem = dojo.query("tr.movieFormatLengthRow", self.movieDropDownContent)[0];
+ self.movieWidthHeightLengthRowElem = dojo.query("tr.movieWidthHeightLengthRow", self.movieDropDownContent)[0];
+ self.movieDnDArea = dojo.query("div.dndArea", self.movieDropDownContent)[0];
+
+ self.createMovieThumb = function(item, mode) {
+ if (mode == 'avatar') {
+ // when dragged
+ var avatar = dojo.create( 'div', { innerHTML: item.data });
+ var avatarPose = dojo.clone(self.pose);
+ avatarPose.width = 60;
+ avatarPose.height = 60;
+ var avatarImgUrl = urlSuffixForPose(avatarPose);
+ avatar.innerHTML = '<img src=' + self.imageURL + avatarImgUrl + ' /> ';
+ item.srcEcc = "VRMLViewer";
+ item.iconPoseUrl = self.imageURL + avatarImgUrl;
+ item.imageURL = self.imageURL;
+ item.serverURL = self.serverURL;
+ item.pose = avatarPose;
+ return {node: avatar, data: item, type: item.type};
+ } else {
+
+ // when added to list
+ var thumb = domConst.toDom("\
+ <div>\
+ <table><tr><td>\
+ <img class=\"movieThumb\"/>\
+ <img class=\"removeThumb\" style=\"vertical-align: top; margin: -3px 0px 0px -8px; width: 20px; height: 20px;\"/>\
+ </td><td align=\"left\">\
+ <table><tr>\
+ <td>Frame:</td><td><div class=\"relFrameLength\"/></td>\
+ <td><div class=\"fillInSeries\" \></td>\
+ </tr><tr>\
+ <td>Transition:</td><td><div class=\"relTransitionLength\"/></td>\
+ </tr></table>\
+ </td></tr></table>\
+ </div>\
+ ");
+ thumb = dojo.query("div", thumb)[0];
+
+ var thumbImgElem = dojo.query("img.movieThumb", thumb)[0];
+ var removeImgElem = dojo.query("img.removeThumb", thumb)[0];
+ var relFrameLengthElem = dojo.query("div.relFrameLength", thumb)[0];
+ var relTransitionLengthElem = dojo.query("div.relTransitionLength", thumb)[0];
+ var fillInSeriesElem = dojo.query("div.fillInSeries", thumb)[0];
+
+ item.getThisAndNeighborsFromDnD = function() {
+ var thisAndNeighbors = {};
+ self.addToMovieHandler.forInItems(function(obj, key, ctx) {
+ if (obj.data === item) {
+ thisAndNeighbors.this = { key: key, obj: obj };
+ } else {
+ thisAndNeighbors.before = { key: key, obj: obj };
+ }
+ if (thisAndNeighbors.this) {
+ thisAndNeighbors.after = { key: key, obj: obj };
+ return thisAndNeighbors;
+ }
+ });
+ return thisAndNeighbors;
+ };
+
+ item.relFrameLengthSlider = new HorizontalSlider({
+ value: 50,
+ title: "Relative Duration of Frame",
+ style: "width:150px;"
+ }, relFrameLengthElem);
+
+ item.relTransitionLengthSlider = new HorizontalSlider({
+ value: 100,
+ title: "Relative Duration of Transition",
+ style: "width:150px;"
+ }, relTransitionLengthElem);
+
+ removeImgElem.onclick = function() {
+ var thisItem = item.getThisAndNeighborsFromDnD();
+ if (thisItem.this) {
+ // haha - what a mess!
+ self.addToMovieHandler.selectNone();
+ self.addToMovieHandler.selection[thisItem.this.key] = thisItem.this.obj;
+ self.addToMovieHandler.deleteSelectedNodes();
+ }
+ // disable create button if this was the last one
+ if (!thisItem.after || !thisItem.before) {
+ self.movieCreateButton.setAttribute('disabled', true);
+ }
+ }
+
+ item.fillInSeriesButton = new Button({
+ label: "Insert Series",
+ style: "display: none;",
+ onClick: function(){
+ alert("foo");
+ }
+ }, fillInSeriesElem);
+
+ removeImgElem.src = self.resRoot + "img/close.png";
+
+ var thumbPose = dojo.clone(self.pose);
+ thumbPose.width = self.pose.width / 10;
+ thumbPose.height = self.pose.height / 10;
+ var thumbImgUrl = urlSuffixForPose(thumbPose);
+
+ thumbImgElem.src = self.imageURL + thumbImgUrl;
+ // removeImgElem.src = self.resRoot + 'img/close.png';
+
+ item.srcEcc = "VRMLViewer";
+ item.iconPoseUrl = self.imageURL + thumbImgUrl;
+ item.imageURL = self.imageURL;
+ item.serverURL = self.serverURL;
+ item.pose = thumbPose;
+
+ return {node: thumb, data: item, type: item.type};
+ }
+ };
+
+ self.addToMovieHandler = new Source(self.movieDnDArea, {copyOnly: true, creator: self.createMovieThumb});
+
+ self.movieFormatSelection = new Selector({
+ name: "movieFormat",
+ style: "width: 320px",
+ options: []
+ });
+ self.populateMovieCodecs(self.serverURL + '/movie/codecs', self.movieFormatSelection);
+
+ self.movieFormatLengthRowElem.appendChild(dojo.create('td', { innerHTML: 'Format:'} ));
+ self.movieFormatLengthRowElem.appendChild(dojo.create('td', { colspan: "2"}));
+ self.movieFormatLengthRowElem.lastChild.appendChild(self.movieFormatSelection.domNode);
+
+ self.movieHeightSpinner = new NumberSpinner({
+ value: 400,
+ smallDelta: 1,
+ style: "width: 60px",
+ constraints: { min:40, places:0 },
+ });
+
+ self.movieWidthSpinner = new NumberSpinner({
+ value: 600,
+ smallDelta: 1,
+ style: "width: 60px",
+ constraints: { min:40, places:0 },
+ });
+
+ self.movieCreateButton = new Button({
+ label: "Create",
+ disabled: true,
+ onClick: function(){
+
+ var form = document.createElement("form");
+
+ form.setAttribute("method", "post");
+ form.setAttribute("action", self.serverURL + "/movie");
+
+ var submitData = {};
+ submitData.frames = [];
+ submitData.movieLength = self.movieDurationSpinner.value;
+ submitData.format = self.movieFormatSelection.value;
+ submitData.width = self.movieWidthSpinner.value;
+ submitData.height = self.movieHeightSpinner.value;
+
+ self.addToMovieHandler.forInItems(function(obj, key, ctx) {
+ var jsonData = {
+ iconPoseUrl: obj.data.iconPoseUrl,
+ imageURL: obj.data.imageURL,
+ serverURL: obj.data.serverURL,
+ pose: obj.data.pose,
+ relFrameLength: obj.data.relFrameLengthSlider.value,
+ relTransitionLength: obj.data.relTransitionLengthSlider.value,
+ }
+ submitData.frames.push(jsonData);
+ });
+
+ var hiddenField = document.createElement("input");
+ hiddenField.setAttribute("type", "hidden");
+ hiddenField.setAttribute("name", "data");
+ hiddenField.setAttribute("value", JSON.stringify(submitData));
+
+ form.appendChild(hiddenField);
+
+ // this will not save the returned binary file
+ // self.xhr.post({
+ // form: form,
+ // load: function(data){
+ // alert("asd");
+ // }
+ // });
+
+ document.body.appendChild(form);
+ form.submit();
+ document.body.removeChild(form);
+ }
+ });
+
+ self.movieDurationSpinner = new NumberSpinner({
+ value: 10,
+ smallDelta: 1,
+ style: "width: 40px",
+ constraints: { min:0, places:0 },
+ });
+
+ // append format duration cell
+ self.movieWidthHeightLengthRowElem.appendChild(dojo.create('td', { innerHTML: 'Size:'} ));
+ var movieDimensionCell = dojo.create('td');
+ movieDimensionCell.appendChild(self.movieWidthSpinner.domNode);
+ movieDimensionCell.appendChild(dojo.create('span', { innerHTML: "x"} ));
+ movieDimensionCell.appendChild(self.movieHeightSpinner.domNode);
+ movieDimensionCell.appendChild(self.movieDurationSpinner.domNode);
+ movieDimensionCell.appendChild(dojo.create('span', { innerHTML: "sec"} ));
+ self.movieWidthHeightLengthRowElem.appendChild(movieDimensionCell);
+
+ self.movieWidthHeightLengthRowElem.appendChild(dojo.create('td', { align: "right"}));
+ self.movieWidthHeightLengthRowElem.lastChild.appendChild(self.movieCreateButton.domNode);
+
+
+ self.movieToolTip = new TooltipDialog({ content:self.movieDropDownContent });
+ self.movieDropDown = new DropDownButton({
+ label: "Movie",
+ style: "display: none;",
+ dropDown: self.movieToolTip });
+ self.movieDropDownElem.appendChild(self.movieDropDown.domNode);
+
+ self.movieAddButton = new Button({
+ label: "+",
+ style: "margin-left: -10px; display: none;",
+ onClick: function(){
+ if (self.movieFormatSelection.options.length == 0) {
+ self.populateMovieCodecs(self.serverURL + '/movie/codecs', self.movieFormatSelection);
+ }
+ // we could pass item.data here to creator
+ self.addToMovieHandler.insertNodes(false, [ { } ]);
+ self.movieCreateButton.setAttribute('disabled', false);
+
+ }
+ }, self.movieAddButtonElem);
+
+
+ self.resetButton = new Button({
+ label: "Reset",
+ onClick: function(){
+ self.pose.x = 0;
+ self.pose.y = 0;
+ self.pose.pitch = 0;
+ self.pose.roll = 0;
+ self.pose.yaw = 0;
+ self.pose.zoom = 1;
+
+ self.xyHandler.node.style.left = 0;
+ self.xyHandler.node.style.top = 0;
+ self.pitchRollHandler.node.style.left = 0;
+ self.pitchRollHandler.node.style.top = 0;
+ self.yawZoomHandler.node.style.left = 0;
+ self.yawZoomHandler.node.style.top = 0;
+
+ self.updateScene();
+ }
+ }, self.resetButtonElem);
+
+ // do we have parameters for the initial pose?
+ if(self.params && self.params.pose)
+ self.setPose(self.params.imageURL, self.params.pose, self.params.serverURL);
+
+ });
+ });
+
+
+}
diff --git a/apps/samples/vrml/vrml-server.scxml b/apps/samples/vrml/vrml-server.scxml
index 5ee28dd..2f5c4ca 100644
--- a/apps/samples/vrml/vrml-server.scxml
+++ b/apps/samples/vrml/vrml-server.scxml
@@ -179,7 +179,7 @@
<!-- Start the osgconvert invoker to transform 3D files -->
<invoke type="osgconvert" id="osgvonvert.osgb">
- <param name="threads" expr="20" />
+ <param name="threads" expr="4" />
<finalize>
<script>
//dump(_event);
diff --git a/apps/uscxml-browser.cpp b/apps/uscxml-browser.cpp
index fa108f8..566f6bc 100644
--- a/apps/uscxml-browser.cpp
+++ b/apps/uscxml-browser.cpp
@@ -15,10 +15,6 @@
#include <dlfcn.h>
#endif
-#ifdef _WIN32
-#include "XGetopt.h"
-#endif
-
class VerboseMonitor : public uscxml::InterpreterMonitor {
void onStableConfiguration(uscxml::Interpreter interpreter) {
printConfig(interpreter.getConfiguration());
@@ -108,23 +104,6 @@ void customTerminate() {
}
#endif
-void printUsageAndExit() {
- printf("uscxml-browser version " USCXML_VERSION " (" CMAKE_BUILD_TYPE " build - " CMAKE_COMPILER_STRING ")\n");
- printf("Usage\n");
- printf("\tuscxml-browser");
-#ifdef BUILD_AS_PLUGINS
- printf(" [-e pluginPath]");
-#endif
- printf("[-v] [-pN] URL\n");
- printf("\n");
- printf("Options\n");
- printf("\t-v : be verbose\n");
- printf("\t-pN : port for HTTP server\n");
- printf("\t-d : write each configuration as a dot file\n");
- printf("\n");
- exit(1);
-}
-
int main(int argc, char** argv) {
using namespace uscxml;
@@ -136,75 +115,78 @@ int main(int argc, char** argv) {
std::set_terminate(customTerminate);
#endif
- if (argc < 2) {
- printUsageAndExit();
+ InterpreterOptions options = InterpreterOptions::fromCmdLine(argc, argv);
+ if (!options) {
+ InterpreterOptions::printUsageAndExit(argv[0]);
}
-
- bool verbose = false;
- bool useDot = false;
- bool glogIsInitialized = false;
- size_t port = 8080;
+ // setup logging
google::LogToStderr();
-
-#ifndef _WIN32
- opterr = 0;
-#endif
- int option;
- while ((option = getopt(argc, argv, "dvl:e:p:")) != -1) {
- switch(option) {
- case 'l':
- google::InitGoogleLogging(optarg);
- glogIsInitialized = true;
- break;
- case 'e':
- uscxml::Factory::pluginPath = optarg;
- break;
- case 'd':
- useDot = true;
- break;
- case 'p':
- port = strTo<size_t>(optarg);
- break;
- case 'v':
- verbose = true;
- break;
- case '?':
- break;
- default:
- printUsageAndExit();
- break;
- }
+ google::InitGoogleLogging(argv[0]);
+
+ // setup HTTP server
+ HTTPServer::SSLConfig* sslConf = NULL;
+ if (options.certificate.length() > 0) {
+ sslConf = new HTTPServer::SSLConfig();
+ sslConf->privateKey = options.certificate;
+ sslConf->publicKey = options.certificate;
+ sslConf->port = options.httpsPort;
+
+ } else if (options.privateKey.length() > 0 && options.publicKey.length() > 0) {
+ sslConf = new HTTPServer::SSLConfig();
+ sslConf->privateKey = options.privateKey;
+ sslConf->publicKey = options.publicKey;
+ sslConf->port = options.httpsPort;
+
}
+ HTTPServer::getInstance(options.httpPort, sslConf);
+
+ // instantiate and configure interpreters
+ std::list<Interpreter> interpreters;
+ std::map<std::string, InterpreterOptions*>::iterator confIter = options.interpreters.begin();
+ while(confIter != options.interpreters.end()) {
+
+ InterpreterOptions* currOptions = confIter->second;
+ std::string documentURL = confIter->first;
+
+ LOG(INFO) << "Processing " << documentURL;
+ Interpreter interpreter = Interpreter::fromURI(documentURL);
+ if (interpreter) {
+ interpreter.setCmdLineOptions(currOptions->additionalParameters);
+ interpreter.setCapabilities(options.getCapabilities());
+
+ if (options.verbose) {
+ VerboseMonitor* vm = new VerboseMonitor();
+ interpreter.addMonitor(vm);
+ }
+ if (options.useDot) {
+ SCXMLDotWriter* dotWriter = new SCXMLDotWriter();
+ interpreter.addMonitor(dotWriter);
+ }
+
+ interpreters.push_back(interpreter);
- if (!glogIsInitialized)
- google::InitGoogleLogging(argv[0]);
-
-// for (int i = 0; i < argc; i++)
-// std::cout << argv[i] << std::endl;
-// std::cout << optind << std::endl;
-
- // intialize http server on given port
- HTTPServer::getInstance(port);
+ } else {
+ LOG(ERROR) << "Cannot create interpreter from " << documentURL;
+ }
+ confIter++;
+ }
- LOG(INFO) << "Processing " << argv[optind];
- Interpreter interpreter = Interpreter::fromURI(argv[optind]);
- if (interpreter) {
- interpreter.setCmdLineOptions(argc, argv);
- // interpreter->setCapabilities(Interpreter::CAN_NOTHING);
- // interpreter->setCapabilities(Interpreter::CAN_BASIC_HTTP | Interpreter::CAN_GENERIC_HTTP);
+ // start interpreters
+ std::list<Interpreter>::iterator interpreterIter = interpreters.begin();
+ while(interpreterIter != interpreters.end()) {
+ interpreterIter->start();
+ interpreterIter++;
+ }
- if (verbose) {
- VerboseMonitor* vm = new VerboseMonitor();
- interpreter.addMonitor(vm);
- }
- if (useDot) {
- SCXMLDotWriter* dotWriter = new SCXMLDotWriter();
- interpreter.addMonitor(dotWriter);
+ // call from main thread for UI events
+ while(interpreters.size() > 0) {
+ interpreterIter = interpreters.begin();
+ while(interpreterIter != interpreters.end()) {
+ interpreterIter->runOnMainThread(25);
+ interpreterIter++;
}
-
- interpreter.start();
- while(interpreter.runOnMainThread(25));
}
+
return EXIT_SUCCESS;
} \ No newline at end of file
diff --git a/config.h.in b/config.h.in
index 93e4e4a..2498d12 100644
--- a/config.h.in
+++ b/config.h.in
@@ -66,6 +66,8 @@
#cmakedefine PROTOBUF_FOUND
#cmakedefine CORELOCATION_FOUND
#cmakedefine LIBPURPLE_FOUND
+#cmakedefine OPENSSL_FOUND
+#cmakedefine EVENT_SSL_FOUND
/** Header files we found */
#cmakedefine HAS_UNISTD_H
diff --git a/contrib/cmake/FindEVENT.cmake b/contrib/cmake/FindEVENT.cmake
index 7904b6a..418ebab 100644
--- a/contrib/cmake/FindEVENT.cmake
+++ b/contrib/cmake/FindEVENT.cmake
@@ -30,6 +30,31 @@ else()
endif()
endif()
+
+
+FIND_LIBRARY(EVENT_SSL_LIBRARY_RELEASE
+ NAMES event_openssl libevent_openssl
+ HINTS $ENV{EVENT_SRC}/.libs/
+ SET(EVENT_SSL_FOUND ON)
+)
+if (EVENT_SSL_LIBRARY_RELEASE)
+ list(APPEND EVENT_LIBRARY optimized ${EVENT_SSL_LIBRARY_RELEASE})
+endif()
+
+FIND_LIBRARY(EVENT_SSL_LIBRARY_DEBUG
+ NAMES event_openssl_d libevent_openssl_d
+ HINTS $ENV{EVENT_SRC}/.libs/
+)
+if (EVENT_SSL_LIBRARY_DEBUG)
+ list(APPEND EVENT_LIBRARY debug ${EVENT_SSL_LIBRARY_DEBUG})
+else()
+ if (UNIX AND EVENT_SSL_LIBRARY_RELEASE)
+ list(APPEND EVENT_LIBRARY debug ${EVENT_SSL_LIBRARY_RELEASE})
+ endif()
+endif()
+
+
+
if (NOT WIN32)
FIND_LIBRARY(EVENT_LIBRARY_THREADS
NAMES event_pthreads
@@ -51,6 +76,8 @@ if (NOT WIN32)
endif()
+# message(FATAL_ERROR "EVENT_LIBRARY: ${EVENT_LIBRARY}")
+
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(EVENT DEFAULT_MSG EVENT_LIBRARY EVENT_INCLUDE_DIR)
MARK_AS_ADVANCED(EVENT_LIBRARY EVENT_INCLUDE_DIR)
diff --git a/contrib/cmake/USCXMLMacros.cmake b/contrib/cmake/USCXMLMacros.cmake
index eb325e8..d5ea05f 100644
--- a/contrib/cmake/USCXMLMacros.cmake
+++ b/contrib/cmake/USCXMLMacros.cmake
@@ -56,3 +56,4 @@ function(INSTALL_EXECUTABLE)
COMPONENT ${INSTALL_EXECUTABLE_COMPONENT}
PERMISSIONS WORLD_EXECUTE OWNER_EXECUTE GROUP_EXECUTE OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)
endfunction()
+
diff --git a/contrib/cmake/cotire.cmake b/contrib/cmake/cotire.cmake
new file mode 100644
index 0000000..16cb90f
--- /dev/null
+++ b/contrib/cmake/cotire.cmake
@@ -0,0 +1,3239 @@
+# - cotire (compile time reducer)
+#
+# See the cotire manual for usage hints.
+#
+#=============================================================================
+# Copyright 2012-2013 Sascha Kratky
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use,
+# copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following
+# conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#=============================================================================
+
+if(__COTIRE_INCLUDED)
+ return()
+endif()
+set(__COTIRE_INCLUDED TRUE)
+
+# call cmake_minimum_required, but prevent modification of the CMake policy stack in include mode
+# cmake_minimum_required also sets the policy version as a side effect, which we have to avoid
+if (NOT CMAKE_SCRIPT_MODE_FILE)
+ cmake_policy(PUSH)
+endif()
+# we need the CMake variables CMAKE_SCRIPT_MODE_FILE and CMAKE_ARGV available since 2.8.5
+# we need APPEND_STRING option for set_property available since 2.8.6
+cmake_minimum_required(VERSION 2.8.6)
+if (NOT CMAKE_SCRIPT_MODE_FILE)
+ cmake_policy(POP)
+endif()
+
+set (COTIRE_CMAKE_MODULE_FILE "${CMAKE_CURRENT_LIST_FILE}")
+set (COTIRE_CMAKE_MODULE_VERSION "1.4.3")
+
+include(CMakeParseArguments)
+include(ProcessorCount)
+
+function (cotire_determine_compiler_version _language _versionPrefix)
+ if (NOT ${_versionPrefix}_VERSION)
+ # use CMake's predefined compiler version variable (available since CMake 2.8.8)
+ if (DEFINED CMAKE_${_language}_COMPILER_VERSION)
+ set (${_versionPrefix}_VERSION "${CMAKE_${_language}_COMPILER_VERSION}")
+ elseif (WIN32)
+ # cl.exe messes with the output streams unless the environment variable VS_UNICODE_OUTPUT is cleared
+ unset (ENV{VS_UNICODE_OUTPUT})
+ string (STRIP "${CMAKE_${_language}_COMPILER_ARG1}" _compilerArg1)
+ execute_process (COMMAND ${CMAKE_${_language}_COMPILER} ${_compilerArg1}
+ ERROR_VARIABLE _versionLine OUTPUT_QUIET TIMEOUT 10)
+ string (REGEX REPLACE ".*Version *([0-9]+(\\.[0-9]+)*).*" "\\1" ${_versionPrefix}_VERSION "${_versionLine}")
+ else()
+ # assume GCC like command line interface
+ string (STRIP "${CMAKE_${_language}_COMPILER_ARG1}" _compilerArg1)
+ execute_process (COMMAND ${CMAKE_${_language}_COMPILER} ${_compilerArg1} "-dumpversion"
+ OUTPUT_VARIABLE ${_versionPrefix}_VERSION
+ RESULT_VARIABLE _result
+ OUTPUT_STRIP_TRAILING_WHITESPACE TIMEOUT 10)
+ if (_result)
+ set (${_versionPrefix}_VERSION "")
+ endif()
+ endif()
+ if (${_versionPrefix}_VERSION)
+ set (${_versionPrefix}_VERSION "${${_versionPrefix}_VERSION}" CACHE INTERNAL "${_language} compiler version")
+ endif()
+ set (${_versionPrefix}_VERSION "${${_versionPrefix}_VERSION}" PARENT_SCOPE)
+ if (COTIRE_DEBUG)
+ message (STATUS "${CMAKE_${_language}_COMPILER} version ${${_versionPrefix}_VERSION}")
+ endif()
+ endif()
+endfunction()
+
+function (cotire_get_source_file_extension _sourceFile _extVar)
+ # get_filename_component returns extension from first occurrence of . in file name
+ # this function computes the extension from last occurrence of . in file name
+ string (FIND "${_sourceFile}" "." _index REVERSE)
+ if (_index GREATER -1)
+ math (EXPR _index "${_index} + 1")
+ string (SUBSTRING "${_sourceFile}" ${_index} -1 _sourceExt)
+ else()
+ set (_sourceExt "")
+ endif()
+ set (${_extVar} "${_sourceExt}" PARENT_SCOPE)
+endfunction()
+
+macro (cotire_check_is_path_relative_to _path _isRelativeVar)
+ set (${_isRelativeVar} FALSE)
+ if (IS_ABSOLUTE "${_path}")
+ foreach (_dir ${ARGN})
+ file (RELATIVE_PATH _relPath "${_dir}" "${_path}")
+ if (NOT _relPath OR (NOT IS_ABSOLUTE "${_relPath}" AND NOT "${_relPath}" MATCHES "^\\.\\."))
+ set (${_isRelativeVar} TRUE)
+ break()
+ endif()
+ endforeach()
+ endif()
+endmacro()
+
+function (cotire_filter_language_source_files _language _sourceFilesVar _excludedSourceFilesVar _cotiredSourceFilesVar)
+ set (_sourceFiles "")
+ set (_excludedSourceFiles "")
+ set (_cotiredSourceFiles "")
+ if (CMAKE_${_language}_SOURCE_FILE_EXTENSIONS)
+ set (_languageExtensions "${CMAKE_${_language}_SOURCE_FILE_EXTENSIONS}")
+ else()
+ set (_languageExtensions "")
+ endif()
+ if (CMAKE_${_language}_IGNORE_EXTENSIONS)
+ set (_ignoreExtensions "${CMAKE_${_language}_IGNORE_EXTENSIONS}")
+ else()
+ set (_ignoreExtensions "")
+ endif()
+ if (COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS)
+ set (_excludeExtensions "${COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS}")
+ else()
+ set (_excludeExtensions "")
+ endif()
+ if (COTIRE_DEBUG)
+ message (STATUS "${_language} source file extensions: ${_languageExtensions}")
+ message (STATUS "${_language} ignore extensions: ${_ignoreExtensions}")
+ message (STATUS "${_language} exclude extensions: ${_excludeExtensions}")
+ endif()
+ foreach (_sourceFile ${ARGN})
+ get_source_file_property(_sourceIsHeaderOnly "${_sourceFile}" HEADER_FILE_ONLY)
+ get_source_file_property(_sourceIsExternal "${_sourceFile}" EXTERNAL_OBJECT)
+ get_source_file_property(_sourceIsSymbolic "${_sourceFile}" SYMBOLIC)
+ get_source_file_property(_sourceLanguage "${_sourceFile}" LANGUAGE)
+ set (_sourceIsFiltered FALSE)
+ if (NOT _sourceIsHeaderOnly AND NOT _sourceIsExternal AND NOT _sourceIsSymbolic)
+ cotire_get_source_file_extension("${_sourceFile}" _sourceExt)
+ if (_sourceExt)
+ list (FIND _ignoreExtensions "${_sourceExt}" _ignoreIndex)
+ if (_ignoreIndex LESS 0)
+ list (FIND _excludeExtensions "${_sourceExt}" _excludeIndex)
+ if (_excludeIndex GREATER -1)
+ list (APPEND _excludedSourceFiles "${_sourceFile}")
+ else()
+ list (FIND _languageExtensions "${_sourceExt}" _sourceIndex)
+ if (_sourceIndex GREATER -1)
+ set (_sourceIsFiltered TRUE)
+ elseif ("${_sourceLanguage}" STREQUAL "${_language}")
+ # add to excluded sources, if file is not ignored and has correct language without having the correct extension
+ list (APPEND _excludedSourceFiles "${_sourceFile}")
+ endif()
+ endif()
+ endif()
+ endif()
+ endif()
+ if (COTIRE_DEBUG)
+ message (STATUS "${_sourceFile} filtered=${_sourceIsFiltered} language=${_sourceLanguage} header=${_sourceIsHeaderOnly}")
+ endif()
+ if (_sourceIsFiltered)
+ get_source_file_property(_sourceIsExcluded "${_sourceFile}" COTIRE_EXCLUDED)
+ get_source_file_property(_sourceIsCotired "${_sourceFile}" COTIRE_TARGET)
+ get_source_file_property(_sourceCompileFlags "${_sourceFile}" COMPILE_FLAGS)
+ if (COTIRE_DEBUG)
+ message (STATUS "${_sourceFile} excluded=${_sourceIsExcluded} cotired=${_sourceIsCotired} compileFlags=${_sourceCompileFlags}")
+ endif()
+ if (_sourceIsCotired)
+ list (APPEND _cotiredSourceFiles "${_sourceFile}")
+ elseif (_sourceIsExcluded OR _sourceCompileFlags)
+ list (APPEND _excludedSourceFiles "${_sourceFile}")
+ else()
+ list (APPEND _sourceFiles "${_sourceFile}")
+ endif()
+ endif()
+ endforeach()
+ if (COTIRE_DEBUG)
+ message (STATUS "All: ${ARGN}")
+ message (STATUS "${_language}: ${_sourceFiles}")
+ message (STATUS "Excluded: ${_excludedSourceFiles}")
+ message (STATUS "Cotired: ${_cotiredSourceFiles}")
+ endif()
+ set (${_sourceFilesVar} ${_sourceFiles} PARENT_SCOPE)
+ set (${_excludedSourceFilesVar} ${_excludedSourceFiles} PARENT_SCOPE)
+ set (${_cotiredSourceFilesVar} ${_cotiredSourceFiles} PARENT_SCOPE)
+endfunction()
+
+function (cotire_get_objects_with_property_on _filteredObjectsVar _property _type)
+ set (_filteredObjects "")
+ foreach (_object ${ARGN})
+ get_property(_isSet ${_type} "${_object}" PROPERTY ${_property} SET)
+ if (_isSet)
+ get_property(_propertyValue ${_type} "${_object}" PROPERTY ${_property})
+ if (_propertyValue)
+ list (APPEND _filteredObjects "${_object}")
+ endif()
+ endif()
+ endforeach()
+ set (${_filteredObjectsVar} ${_filteredObjects} PARENT_SCOPE)
+endfunction()
+
+function (cotire_get_objects_with_property_off _filteredObjectsVar _property _type)
+ set (_filteredObjects "")
+ foreach (_object ${ARGN})
+ get_property(_isSet ${_type} "${_object}" PROPERTY ${_property} SET)
+ if (_isSet)
+ get_property(_propertyValue ${_type} "${_object}" PROPERTY ${_property})
+ if (NOT _propertyValue)
+ list (APPEND _filteredObjects "${_object}")
+ endif()
+ endif()
+ endforeach()
+ set (${_filteredObjectsVar} ${_filteredObjects} PARENT_SCOPE)
+endfunction()
+
+function (cotire_get_source_file_property_values _valuesVar _property)
+ set (_values "")
+ foreach (_sourceFile ${ARGN})
+ get_source_file_property(_propertyValue "${_sourceFile}" ${_property})
+ if (_propertyValue)
+ list (APPEND _values "${_propertyValue}")
+ endif()
+ endforeach()
+ set (${_valuesVar} ${_values} PARENT_SCOPE)
+endfunction()
+
+function (cotrie_resolve_config_properites _configurations _propertiesVar)
+ set (_properties "")
+ foreach (_property ${ARGN})
+ if ("${_property}" MATCHES "<CONFIG>")
+ foreach (_config ${_configurations})
+ string (TOUPPER "${_config}" _upperConfig)
+ string (REPLACE "<CONFIG>" "${_upperConfig}" _configProperty "${_property}")
+ list (APPEND _properties ${_configProperty})
+ endforeach()
+ else()
+ list (APPEND _properties ${_property})
+ endif()
+ endforeach()
+ set (${_propertiesVar} ${_properties} PARENT_SCOPE)
+endfunction()
+
+function (cotrie_copy_set_properites _configurations _type _source _target)
+ cotrie_resolve_config_properites("${_configurations}" _properties ${ARGN})
+ foreach (_property ${_properties})
+ get_property(_isSet ${_type} ${_source} PROPERTY ${_property} SET)
+ if (_isSet)
+ get_property(_propertyValue ${_type} ${_source} PROPERTY ${_property})
+ set_property(${_type} ${_target} PROPERTY ${_property} "${_propertyValue}")
+ endif()
+ endforeach()
+endfunction()
+
+function (cotire_filter_compile_flags _language _flagFilter _matchedOptionsVar _unmatchedOptionsVar)
+ if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel")
+ set (_flagPrefix "[/-]")
+ else()
+ set (_flagPrefix "--?")
+ endif()
+ set (_optionFlag "")
+ set (_matchedOptions "")
+ set (_unmatchedOptions "")
+ foreach (_compileFlag ${ARGN})
+ if (_compileFlag)
+ if (_optionFlag AND NOT "${_compileFlag}" MATCHES "^${_flagPrefix}")
+ # option with separate argument
+ list (APPEND _matchedOptions "${_compileFlag}")
+ set (_optionFlag "")
+ elseif ("${_compileFlag}" MATCHES "^(${_flagPrefix})(${_flagFilter})$")
+ # remember option
+ set (_optionFlag "${CMAKE_MATCH_2}")
+ elseif ("${_compileFlag}" MATCHES "^(${_flagPrefix})(${_flagFilter})(.+)$")
+ # option with joined argument
+ list (APPEND _matchedOptions "${CMAKE_MATCH_3}")
+ set (_optionFlag "")
+ else()
+ # flush remembered option
+ if (_optionFlag)
+ list (APPEND _matchedOptions "${_optionFlag}")
+ set (_optionFlag "")
+ endif()
+ # add to unfiltered options
+ list (APPEND _unmatchedOptions "${_compileFlag}")
+ endif()
+ endif()
+ endforeach()
+ if (_optionFlag)
+ list (APPEND _matchedOptions "${_optionFlag}")
+ endif()
+ if (COTIRE_DEBUG)
+ message (STATUS "Filter ${_flagFilter}")
+ if (_matchedOptions)
+ message (STATUS "Matched ${_matchedOptions}")
+ endif()
+ if (_unmatchedOptions)
+ message (STATUS "Unmatched ${_unmatchedOptions}")
+ endif()
+ endif()
+ set (${_matchedOptionsVar} ${_matchedOptions} PARENT_SCOPE)
+ set (${_unmatchedOptionsVar} ${_unmatchedOptions} PARENT_SCOPE)
+endfunction()
+
+function (cotire_get_target_compile_flags _config _language _directory _target _flagsVar)
+ string (TOUPPER "${_config}" _upperConfig)
+ # collect options from CMake language variables
+ set (_compileFlags "")
+ if (CMAKE_${_language}_FLAGS)
+ set (_compileFlags "${_compileFlags} ${CMAKE_${_language}_FLAGS}")
+ endif()
+ if (CMAKE_${_language}_FLAGS_${_upperConfig})
+ set (_compileFlags "${_compileFlags} ${CMAKE_${_language}_FLAGS_${_upperConfig}}")
+ endif()
+ if (_target)
+ # add option from CMake target type variable
+ get_target_property(_targetType ${_target} TYPE)
+ if (POLICY CMP0018)
+ # handle POSITION_INDEPENDENT_CODE property introduced with CMake 2.8.9 if policy CMP0018 is turned on
+ cmake_policy(GET CMP0018 _PIC_Policy)
+ else()
+ # default to old behavior
+ set (_PIC_Policy "OLD")
+ endif()
+ if (COTIRE_DEBUG)
+ message(STATUS "CMP0018=${_PIC_Policy}")
+ endif()
+ if (_PIC_Policy STREQUAL "NEW")
+ # NEW behavior: honor the POSITION_INDEPENDENT_CODE target property
+ get_target_property(_targetPIC ${_target} POSITION_INDEPENDENT_CODE)
+ if (_targetPIC)
+ if (_targetType STREQUAL "EXECUTABLE" AND CMAKE_${_language}_COMPILE_OPTIONS_PIE)
+ set (_compileFlags "${_compileFlags} ${CMAKE_${_language}_COMPILE_OPTIONS_PIE}")
+ elseif (CMAKE_${_language}_COMPILE_OPTIONS_PIC)
+ set (_compileFlags "${_compileFlags} ${CMAKE_${_language}_COMPILE_OPTIONS_PIC}")
+ endif()
+ endif()
+ else()
+ # OLD behavior or policy not set: use the value of CMAKE_SHARED_LIBRARY_<Lang>_FLAGS
+ if (_targetType STREQUAL "MODULE_LIBRARY")
+ # flags variable for module library uses different name SHARED_MODULE
+ # (e.g., CMAKE_SHARED_MODULE_C_FLAGS)
+ set (_targetType SHARED_MODULE)
+ endif()
+ if (CMAKE_${_targetType}_${_language}_FLAGS)
+ set (_compileFlags "${_compileFlags} ${CMAKE_${_targetType}_${_language}_FLAGS}")
+ endif()
+ endif()
+ endif()
+ if (_directory)
+ # add_definitions may have been used to add flags to the compiler command
+ get_directory_property(_dirDefinitions DIRECTORY "${_directory}" DEFINITIONS)
+ if (_dirDefinitions)
+ set (_compileFlags "${_compileFlags} ${_dirDefinitions}")
+ endif()
+ endif()
+ if (_target)
+ # add target compile options
+ get_target_property(_targetflags ${_target} COMPILE_FLAGS)
+ if (_targetflags)
+ set (_compileFlags "${_compileFlags} ${_targetflags}")
+ endif()
+ endif()
+ if (UNIX)
+ separate_arguments(_compileFlags UNIX_COMMAND "${_compileFlags}")
+ elseif(WIN32)
+ separate_arguments(_compileFlags WINDOWS_COMMAND "${_compileFlags}")
+ else()
+ separate_arguments(_compileFlags)
+ endif()
+ # platform specific flags
+ if (APPLE)
+ get_target_property(_architectures ${_target} OSX_ARCHITECTURES_${_upperConfig})
+ if (NOT _architectures)
+ get_target_property(_architectures ${_target} OSX_ARCHITECTURES)
+ endif()
+ foreach (_arch ${_architectures})
+ list (APPEND _compileFlags "-arch" "${_arch}")
+ endforeach()
+ if (CMAKE_OSX_SYSROOT AND CMAKE_OSX_SYSROOT_DEFAULT AND CMAKE_${_language}_HAS_ISYSROOT)
+ if (NOT "${CMAKE_OSX_SYSROOT}" STREQUAL "${CMAKE_OSX_SYSROOT_DEFAULT}")
+ list (APPEND _compileFlags "-isysroot" "${CMAKE_OSX_SYSROOT}")
+ endif()
+ endif()
+ if (CMAKE_OSX_DEPLOYMENT_TARGET AND CMAKE_${_language}_OSX_DEPLOYMENT_TARGET_FLAG)
+ list (APPEND _compileFlags "${CMAKE_${_language}_OSX_DEPLOYMENT_TARGET_FLAG}${CMAKE_OSX_DEPLOYMENT_TARGET}")
+ endif()
+ endif()
+ if (COTIRE_DEBUG AND _compileFlags)
+ message (STATUS "Target ${_target} compile flags ${_compileFlags}")
+ endif()
+ set (${_flagsVar} ${_compileFlags} PARENT_SCOPE)
+endfunction()
+
+function (cotire_get_target_include_directories _config _language _targetSourceDir _targetBinaryDir _target _includeDirsVar)
+ set (_includeDirs "")
+ # default include dirs
+ if (CMAKE_INCLUDE_CURRENT_DIR)
+ list (APPEND _includeDirs "${_targetBinaryDir}")
+ list (APPEND _includeDirs "${_targetSourceDir}")
+ endif()
+ # parse additional include directories from target compile flags
+ set (_targetFlags "")
+ cotire_get_target_compile_flags("${_config}" "${_language}" "${_targetSourceDir}" "${_target}" _targetFlags)
+ cotire_filter_compile_flags("${_language}" "I" _dirs _ignore ${_targetFlags})
+ if (_dirs)
+ list (APPEND _includeDirs ${_dirs})
+ endif()
+ # target include directories
+ get_directory_property(_dirs DIRECTORY "${_targetSourceDir}" INCLUDE_DIRECTORIES)
+ if (_target)
+ get_target_property(_targetDirs ${_target} INCLUDE_DIRECTORIES)
+ if (_targetDirs)
+ list (APPEND _dirs ${_targetDirs})
+ list (REMOVE_DUPLICATES _dirs)
+ endif()
+ endif()
+ list (LENGTH _includeDirs _projectInsertIndex)
+ foreach (_dir ${_dirs})
+ if (CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE)
+ cotire_check_is_path_relative_to("${_dir}" _isRelative "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}")
+ if (_isRelative)
+ list (LENGTH _includeDirs _len)
+ if (_len EQUAL _projectInsertIndex)
+ list (APPEND _includeDirs "${_dir}")
+ else()
+ list (INSERT _includeDirs _projectInsertIndex "${_dir}")
+ endif()
+ math (EXPR _projectInsertIndex "${_projectInsertIndex} + 1")
+ else()
+ list (APPEND _includeDirs "${_dir}")
+ endif()
+ else()
+ list (APPEND _includeDirs "${_dir}")
+ endif()
+ endforeach()
+ list (REMOVE_DUPLICATES _includeDirs)
+ if (CMAKE_${_language}_IMPLICIT_INCLUDE_DIRECTORIES)
+ list (REMOVE_ITEM _includeDirs ${CMAKE_${_language}_IMPLICIT_INCLUDE_DIRECTORIES})
+ endif()
+ if (COTIRE_DEBUG AND _includeDirs)
+ message (STATUS "Target ${_target} include dirs ${_includeDirs}")
+ endif()
+ set (${_includeDirsVar} ${_includeDirs} PARENT_SCOPE)
+endfunction()
+
+macro (cotire_make_C_identifier _identifierVar _str)
+ # mimic CMake SystemTools::MakeCindentifier behavior
+ if ("${_str}" MATCHES "^[0-9].+$")
+ set (_str "_${str}")
+ endif()
+ string (REGEX REPLACE "[^a-zA-Z0-9]" "_" ${_identifierVar} "${_str}")
+endmacro()
+
+function (cotire_get_target_export_symbol _target _exportSymbolVar)
+ set (_exportSymbol "")
+ get_target_property(_targetType ${_target} TYPE)
+ get_target_property(_enableExports ${_target} ENABLE_EXPORTS)
+ if (_targetType MATCHES "(SHARED|MODULE)_LIBRARY" OR
+ (_targetType STREQUAL "EXECUTABLE" AND _enableExports))
+ get_target_property(_exportSymbol ${_target} DEFINE_SYMBOL)
+ if (NOT _exportSymbol)
+ set (_exportSymbol "${_target}_EXPORTS")
+ endif()
+ cotire_make_C_identifier(_exportSymbol "${_exportSymbol}")
+ endif()
+ set (${_exportSymbolVar} ${_exportSymbol} PARENT_SCOPE)
+endfunction()
+
+function (cotire_get_target_compile_definitions _config _language _directory _target _definitionsVar)
+ string (TOUPPER "${_config}" _upperConfig)
+ set (_configDefinitions "")
+ # CMAKE_INTDIR for multi-configuration build systems
+ if (NOT "${CMAKE_CFG_INTDIR}" STREQUAL ".")
+ list (APPEND _configDefinitions "CMAKE_INTDIR=\"${_config}\"")
+ endif()
+ # target export define symbol
+ cotire_get_target_export_symbol("${_target}" _defineSymbol)
+ if (_defineSymbol)
+ list (APPEND _configDefinitions "${_defineSymbol}")
+ endif()
+ # directory compile definitions
+ get_directory_property(_definitions DIRECTORY "${_directory}" COMPILE_DEFINITIONS)
+ if (_definitions)
+ list (APPEND _configDefinitions ${_definitions})
+ endif()
+ get_directory_property(_definitions DIRECTORY "${_directory}" COMPILE_DEFINITIONS_${_upperConfig})
+ if (_definitions)
+ list (APPEND _configDefinitions ${_definitions})
+ endif()
+ # target compile definitions
+ get_target_property(_definitions ${_target} COMPILE_DEFINITIONS)
+ if (_definitions)
+ list (APPEND _configDefinitions ${_definitions})
+ endif()
+ get_target_property(_definitions ${_target} COMPILE_DEFINITIONS_${_upperConfig})
+ if (_definitions)
+ list (APPEND _configDefinitions ${_definitions})
+ endif()
+ # parse additional compile definitions from target compile flags
+ # and don't look at directory compile definitions, which we already handled
+ set (_targetFlags "")
+ cotire_get_target_compile_flags("${_config}" "${_language}" "" "${_target}" _targetFlags)
+ cotire_filter_compile_flags("${_language}" "D" _definitions _ignore ${_targetFlags})
+ if (_definitions)
+ list (APPEND _configDefinitions ${_definitions})
+ endif()
+ list (REMOVE_DUPLICATES _configDefinitions)
+ if (COTIRE_DEBUG AND _configDefinitions)
+ message (STATUS "Target ${_target} compile definitions ${_configDefinitions}")
+ endif()
+ set (${_definitionsVar} ${_configDefinitions} PARENT_SCOPE)
+endfunction()
+
+function (cotire_get_target_compiler_flags _config _language _directory _target _compilerFlagsVar)
+ # parse target compile flags omitting compile definitions and include directives
+ set (_targetFlags "")
+ cotire_get_target_compile_flags("${_config}" "${_language}" "${_directory}" "${_target}" _targetFlags)
+ set (_compilerFlags "")
+ cotire_filter_compile_flags("${_language}" "[ID]" _ignore _compilerFlags ${_targetFlags})
+ if (COTIRE_DEBUG AND _compilerFlags)
+ message (STATUS "Target ${_target} compiler flags ${_compilerFlags}")
+ endif()
+ set (${_compilerFlagsVar} ${_compilerFlags} PARENT_SCOPE)
+endfunction()
+
+function (cotire_add_sys_root_paths _pathsVar)
+ if (APPLE)
+ if (CMAKE_OSX_SYSROOT AND CMAKE_${_language}_HAS_ISYSROOT)
+ foreach (_path IN LISTS ${_pathsVar})
+ if (IS_ABSOLUTE "${_path}")
+ get_filename_component(_path "${CMAKE_OSX_SYSROOT}/${_path}" ABSOLUTE)
+ if (EXISTS "${_path}")
+ list (APPEND ${_pathsVar} "${_path}")
+ endif()
+ endif()
+ endforeach()
+ endif()
+ endif()
+ set (${_pathsVar} ${${_pathsVar}} PARENT_SCOPE)
+ if (COTIRE_DEBUG)
+ message (STATUS "${_pathsVar}=${${_pathsVar}}")
+ endif()
+endfunction()
+
+function (cotire_get_source_extra_properties _sourceFile _pattern _resultVar)
+ set (_extraProperties ${ARGN})
+ set (_result "")
+ if (_extraProperties)
+ list (FIND _extraProperties "${_sourceFile}" _index)
+ if (_index GREATER -1)
+ math (EXPR _index "${_index} + 1")
+ list (LENGTH _extraProperties _len)
+ math (EXPR _len "${_len} - 1")
+ foreach (_index RANGE ${_index} ${_len})
+ list (GET _extraProperties ${_index} _value)
+ if ("${_value}" MATCHES "${_pattern}")
+ list (APPEND _result "${_value}")
+ else()
+ break()
+ endif()
+ endforeach()
+ endif()
+ endif()
+ set (${_resultVar} ${_result} PARENT_SCOPE)
+endfunction()
+
+function (cotire_get_source_compile_definitions _config _language _sourceFile _definitionsVar)
+ set (_compileDefinitions "")
+ if (NOT CMAKE_SCRIPT_MODE_FILE)
+ string (TOUPPER "${_config}" _upperConfig)
+ get_source_file_property(_definitions "${_sourceFile}" COMPILE_DEFINITIONS)
+ if (_definitions)
+ list (APPEND _compileDefinitions ${_definitions})
+ endif()
+ get_source_file_property(_definitions "${_sourceFile}" COMPILE_DEFINITIONS_${_upperConfig})
+ if (_definitions)
+ list (APPEND _compileDefinitions ${_definitions})
+ endif()
+ endif()
+ cotire_get_source_extra_properties("${_sourceFile}" "^[a-zA-Z0-9_]+(=.*)?$" _definitions ${ARGN})
+ if (_definitions)
+ list (APPEND _compileDefinitions ${_definitions})
+ endif()
+ if (COTIRE_DEBUG AND _compileDefinitions)
+ message (STATUS "Source ${_sourceFile} compile definitions ${_compileDefinitions}")
+ endif()
+ set (${_definitionsVar} ${_compileDefinitions} PARENT_SCOPE)
+endfunction()
+
+function (cotire_get_source_files_compile_definitions _config _language _definitionsVar)
+ set (_configDefinitions "")
+ foreach (_sourceFile ${ARGN})
+ cotire_get_source_compile_definitions("${_config}" "${_language}" "${_sourceFile}" _sourceDefinitions)
+ if (_sourceDefinitions)
+ list (APPEND _configDefinitions "${_sourceFile}" ${_sourceDefinitions} "-")
+ endif()
+ endforeach()
+ set (${_definitionsVar} ${_configDefinitions} PARENT_SCOPE)
+endfunction()
+
+function (cotire_get_source_undefs _sourceFile _property _sourceUndefsVar)
+ set (_sourceUndefs "")
+ if (NOT CMAKE_SCRIPT_MODE_FILE)
+ get_source_file_property(_undefs "${_sourceFile}" ${_property})
+ if (_undefs)
+ list (APPEND _sourceUndefs ${_undefs})
+ endif()
+ endif()
+ cotire_get_source_extra_properties("${_sourceFile}" "^[a-zA-Z0-9_]+$" _undefs ${ARGN})
+ if (_undefs)
+ list (APPEND _sourceUndefs ${_undefs})
+ endif()
+ if (COTIRE_DEBUG AND _sourceUndefs)
+ message (STATUS "Source ${_sourceFile} ${_property} undefs ${_sourceUndefs}")
+ endif()
+ set (${_sourceUndefsVar} ${_sourceUndefs} PARENT_SCOPE)
+endfunction()
+
+function (cotire_get_source_files_undefs _property _sourceUndefsVar)
+ set (_sourceUndefs "")
+ foreach (_sourceFile ${ARGN})
+ cotire_get_source_undefs("${_sourceFile}" ${_property} _undefs)
+ if (_undefs)
+ list (APPEND _sourceUndefs "${_sourceFile}" ${_undefs} "-")
+ endif()
+ endforeach()
+ set (${_sourceUndefsVar} ${_sourceUndefs} PARENT_SCOPE)
+endfunction()
+
+macro (cotire_set_cmd_to_prologue _cmdVar)
+ set (${_cmdVar} "${CMAKE_COMMAND}")
+ if (COTIRE_DEBUG)
+ list (APPEND ${_cmdVar} "--warn-uninitialized")
+ endif()
+ list (APPEND ${_cmdVar} "-DCOTIRE_BUILD_TYPE:STRING=$<CONFIGURATION>")
+ if (COTIRE_VERBOSE)
+ list (APPEND ${_cmdVar} "-DCOTIRE_VERBOSE:BOOL=ON")
+ elseif("${CMAKE_GENERATOR}" MATCHES "Makefiles")
+ list (APPEND ${_cmdVar} "-DCOTIRE_VERBOSE:BOOL=$(VERBOSE)")
+ endif()
+endmacro()
+
+function (cotire_init_compile_cmd _cmdVar _language _compilerExe _compilerArg1)
+ if (NOT _compilerExe)
+ set (_compilerExe "${CMAKE_${_language}_COMPILER}")
+ endif()
+ if (NOT _compilerArg1)
+ set (_compilerArg1 ${CMAKE_${_language}_COMPILER_ARG1})
+ endif()
+ string (STRIP "${_compilerArg1}" _compilerArg1)
+ set (${_cmdVar} "${_compilerExe}" ${_compilerArg1} PARENT_SCOPE)
+endfunction()
+
+macro (cotire_add_definitions_to_cmd _cmdVar _language)
+ foreach (_definition ${ARGN})
+ if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel")
+ list (APPEND ${_cmdVar} "/D${_definition}")
+ else()
+ list (APPEND ${_cmdVar} "-D${_definition}")
+ endif()
+ endforeach()
+endmacro()
+
+macro (cotire_add_includes_to_cmd _cmdVar _language)
+ foreach (_include ${ARGN})
+ if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel")
+ file (TO_NATIVE_PATH "${_include}" _include)
+ list (APPEND ${_cmdVar} "/I${_include}")
+ else()
+ list (APPEND ${_cmdVar} "-I${_include}")
+ endif()
+ endforeach()
+endmacro()
+
+macro (cotire_add_compile_flags_to_cmd _cmdVar)
+ foreach (_flag ${ARGN})
+ list (APPEND ${_cmdVar} "${_flag}")
+ endforeach()
+endmacro()
+
+function (cotire_check_file_up_to_date _fileIsUpToDateVar _file)
+ set (${_fileIsUpToDateVar} FALSE PARENT_SCOPE)
+ set (_triggerFile "")
+ foreach (_dependencyFile ${ARGN})
+ if (EXISTS "${_dependencyFile}" AND "${_dependencyFile}" IS_NEWER_THAN "${_file}")
+ set (_triggerFile "${_dependencyFile}")
+ break()
+ endif()
+ endforeach()
+ get_filename_component(_fileName "${_file}" NAME)
+ if (EXISTS "${_file}")
+ if (_triggerFile)
+ if (COTIRE_VERBOSE)
+ message (STATUS "${_fileName} update triggered by ${_triggerFile} change.")
+ endif()
+ else()
+ if (COTIRE_VERBOSE)
+ message (STATUS "${_fileName} is up-to-date.")
+ endif()
+ set (${_fileIsUpToDateVar} TRUE PARENT_SCOPE)
+ endif()
+ else()
+ if (COTIRE_VERBOSE)
+ message (STATUS "${_fileName} does not exist yet.")
+ endif()
+ endif()
+endfunction()
+
+macro (cotire_find_closest_relative_path _headerFile _includeDirs _relPathVar)
+ set (${_relPathVar} "")
+ foreach (_includeDir ${_includeDirs})
+ if (IS_DIRECTORY "${_includeDir}")
+ file (RELATIVE_PATH _relPath "${_includeDir}" "${_headerFile}")
+ if (NOT IS_ABSOLUTE "${_relPath}" AND NOT "${_relPath}" MATCHES "^\\.\\.")
+ string (LENGTH "${${_relPathVar}}" _closestLen)
+ string (LENGTH "${_relPath}" _relLen)
+ if (_closestLen EQUAL 0 OR _relLen LESS _closestLen)
+ set (${_relPathVar} "${_relPath}")
+ endif()
+ endif()
+ elseif ("${_includeDir}" STREQUAL "${_headerFile}")
+ # if path matches exactly, return short non-empty string
+ set (${_relPathVar} "1")
+ break()
+ endif()
+ endforeach()
+endmacro()
+
+macro (cotire_check_header_file_location _headerFile _insideIncudeDirs _outsideIncudeDirs _headerIsInside)
+ # check header path against ignored and honored include directories
+ cotire_find_closest_relative_path("${_headerFile}" "${_insideIncudeDirs}" _insideRelPath)
+ if (_insideRelPath)
+ # header is inside, but could be become outside if there is a shorter outside match
+ cotire_find_closest_relative_path("${_headerFile}" "${_outsideIncudeDirs}" _outsideRelPath)
+ if (_outsideRelPath)
+ string (LENGTH "${_insideRelPath}" _insideRelPathLen)
+ string (LENGTH "${_outsideRelPath}" _outsideRelPathLen)
+ if (_outsideRelPathLen LESS _insideRelPathLen)
+ set (${_headerIsInside} FALSE)
+ else()
+ set (${_headerIsInside} TRUE)
+ endif()
+ else()
+ set (${_headerIsInside} TRUE)
+ endif()
+ else()
+ # header is outside
+ set (${_headerIsInside} FALSE)
+ endif()
+endmacro()
+
+macro (cotire_check_ignore_header_file_path _headerFile _headerIsIgnoredVar)
+ if (NOT EXISTS "${_headerFile}")
+ set (${_headerIsIgnoredVar} TRUE)
+ elseif (IS_DIRECTORY "${_headerFile}")
+ set (${_headerIsIgnoredVar} TRUE)
+ elseif ("${_headerFile}" MATCHES "\\.\\.|[_-]fixed" AND "${_headerFile}" MATCHES "\\.h$")
+ # heuristic: ignore C headers with embedded parent directory references or "-fixed" or "_fixed" in path
+ # these often stem from using GCC #include_next tricks, which may break the precompiled header compilation
+ # with the error message "error: no include path in which to search for header.h"
+ set (${_headerIsIgnoredVar} TRUE)
+ else()
+ set (${_headerIsIgnoredVar} FALSE)
+ endif()
+endmacro()
+
+macro (cotire_check_ignore_header_file_ext _headerFile _ignoreExtensionsVar _headerIsIgnoredVar)
+ # check header file extension
+ cotire_get_source_file_extension("${_headerFile}" _headerFileExt)
+ set (${_headerIsIgnoredVar} FALSE)
+ if (_headerFileExt)
+ list (FIND ${_ignoreExtensionsVar} "${_headerFileExt}" _index)
+ if (_index GREATER -1)
+ set (${_headerIsIgnoredVar} TRUE)
+ endif()
+ endif()
+endmacro()
+
+macro (cotire_parse_line _line _headerFileVar _headerDepthVar)
+ if (MSVC)
+ # cl.exe /showIncludes output looks different depending on the language pack used, e.g.:
+ # English: "Note: including file: C:\directory\file"
+ # German: "Hinweis: Einlesen der Datei: C:\directory\file"
+ # We use a very general regular expression, relying on the presence of the : characters
+ if ("${_line}" MATCHES ":( +)([^:]+:[^:]+)$")
+ # Visual Studio compiler output
+ string (LENGTH "${CMAKE_MATCH_1}" ${_headerDepthVar})
+ get_filename_component(${_headerFileVar} "${CMAKE_MATCH_2}" ABSOLUTE)
+ else()
+ set (${_headerFileVar} "")
+ set (${_headerDepthVar} 0)
+ endif()
+ else()
+ if ("${_line}" MATCHES "^(\\.+) (.*)$")
+ # GCC like output
+ string (LENGTH "${CMAKE_MATCH_1}" ${_headerDepthVar})
+ if (IS_ABSOLUTE "${CMAKE_MATCH_2}")
+ set (${_headerFileVar} "${CMAKE_MATCH_2}")
+ else()
+ get_filename_component(${_headerFileVar} "${CMAKE_MATCH_2}" REALPATH)
+ endif()
+ else()
+ set (${_headerFileVar} "")
+ set (${_headerDepthVar} 0)
+ endif()
+ endif()
+endmacro()
+
+function (cotire_parse_includes _language _scanOutput _ignoredIncudeDirs _honoredIncudeDirs _ignoredExtensions _selectedIncludesVar _unparsedLinesVar)
+ if (WIN32)
+ # prevent CMake macro invocation errors due to backslash characters in Windows paths
+ string (REPLACE "\\" "/" _scanOutput "${_scanOutput}")
+ endif()
+ # canonize slashes
+ string (REPLACE "//" "/" _scanOutput "${_scanOutput}")
+ # prevent semicolon from being interpreted as a line separator
+ string (REPLACE ";" "\\;" _scanOutput "${_scanOutput}")
+ # then separate lines
+ string (REGEX REPLACE "\n" ";" _scanOutput "${_scanOutput}")
+ list (LENGTH _scanOutput _len)
+ # remove duplicate lines to speed up parsing
+ list (REMOVE_DUPLICATES _scanOutput)
+ list (LENGTH _scanOutput _uniqueLen)
+ if (COTIRE_VERBOSE)
+ message (STATUS "Scanning ${_uniqueLen} unique lines of ${_len} for includes")
+ if (_ignoredExtensions)
+ message (STATUS "Ignored extensions: ${_ignoredExtensions}")
+ endif()
+ if (_ignoredIncudeDirs)
+ message (STATUS "Ignored paths: ${_ignoredIncudeDirs}")
+ endif()
+ if (_honoredIncudeDirs)
+ message (STATUS "Included paths: ${_honoredIncudeDirs}")
+ endif()
+ endif()
+ set (_sourceFiles ${ARGN})
+ set (_selectedIncludes "")
+ set (_unparsedLines "")
+ # stack keeps track of inside/outside project status of processed header files
+ set (_headerIsInsideStack "")
+ foreach (_line IN LISTS _scanOutput)
+ if (_line)
+ cotire_parse_line("${_line}" _headerFile _headerDepth)
+ if (_headerFile)
+ cotire_check_header_file_location("${_headerFile}" "${_ignoredIncudeDirs}" "${_honoredIncudeDirs}" _headerIsInside)
+ if (COTIRE_DEBUG)
+ message (STATUS "${_headerDepth}: ${_headerFile} ${_headerIsInside}")
+ endif()
+ # update stack
+ list (LENGTH _headerIsInsideStack _stackLen)
+ if (_headerDepth GREATER _stackLen)
+ math (EXPR _stackLen "${_stackLen} + 1")
+ foreach (_index RANGE ${_stackLen} ${_headerDepth})
+ list (APPEND _headerIsInsideStack ${_headerIsInside})
+ endforeach()
+ else()
+ foreach (_index RANGE ${_headerDepth} ${_stackLen})
+ list (REMOVE_AT _headerIsInsideStack -1)
+ endforeach()
+ list (APPEND _headerIsInsideStack ${_headerIsInside})
+ endif()
+ if (COTIRE_DEBUG)
+ message (STATUS "${_headerIsInsideStack}")
+ endif()
+ # header is a candidate if it is outside project
+ if (NOT _headerIsInside)
+ # get parent header file's inside/outside status
+ if (_headerDepth GREATER 1)
+ math (EXPR _index "${_headerDepth} - 2")
+ list (GET _headerIsInsideStack ${_index} _parentHeaderIsInside)
+ else()
+ set (_parentHeaderIsInside TRUE)
+ endif()
+ # select header file if parent header file is inside project
+ # (e.g., a project header file that includes a standard header file)
+ if (_parentHeaderIsInside)
+ cotire_check_ignore_header_file_path("${_headerFile}" _headerIsIgnored)
+ if (NOT _headerIsIgnored)
+ cotire_check_ignore_header_file_ext("${_headerFile}" _ignoredExtensions _headerIsIgnored)
+ if (NOT _headerIsIgnored)
+ list (APPEND _selectedIncludes "${_headerFile}")
+ else()
+ # fix header's inside status on stack, it is ignored by extension now
+ list (REMOVE_AT _headerIsInsideStack -1)
+ list (APPEND _headerIsInsideStack TRUE)
+ endif()
+ endif()
+ if (COTIRE_DEBUG)
+ message (STATUS "${_headerFile} ${_ignoredExtensions} ${_headerIsIgnored}")
+ endif()
+ endif()
+ endif()
+ else()
+ if (MSVC)
+ # for cl.exe do not keep unparsed lines which solely consist of a source file name
+ string (FIND "${_sourceFiles}" "${_line}" _index)
+ if (_index LESS 0)
+ list (APPEND _unparsedLines "${_line}")
+ endif()
+ else()
+ list (APPEND _unparsedLines "${_line}")
+ endif()
+ endif()
+ endif()
+ endforeach()
+ list (REMOVE_DUPLICATES _selectedIncludes)
+ set (${_selectedIncludesVar} ${_selectedIncludes} PARENT_SCOPE)
+ set (${_unparsedLinesVar} ${_unparsedLines} PARENT_SCOPE)
+endfunction()
+
+function (cotire_scan_includes _includesVar)
+ set(_options "")
+ set(_oneValueArgs COMPILER_ID COMPILER_EXECUTABLE COMPILER_VERSION LANGUAGE UNPARSED_LINES)
+ set(_multiValueArgs COMPILE_DEFINITIONS COMPILE_FLAGS INCLUDE_DIRECTORIES IGNORE_PATH INCLUDE_PATH IGNORE_EXTENSIONS)
+ cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
+ set (_sourceFiles ${_option_UNPARSED_ARGUMENTS})
+ if (NOT _option_LANGUAGE)
+ set (_option_LANGUAGE "CXX")
+ endif()
+ if (NOT _option_COMPILER_ID)
+ set (_option_COMPILER_ID "${CMAKE_${_option_LANGUAGE}_ID}")
+ endif()
+ set (_cmd "${_option_COMPILER_EXECUTABLE}" ${_option_COMPILER_ARG1})
+ cotire_init_compile_cmd(_cmd "${_option_LANGUAGE}" "${_option_COMPILER_EXECUTABLE}" "${_option_COMPILER_ARG1}")
+ cotire_add_definitions_to_cmd(_cmd "${_option_LANGUAGE}" ${_option_COMPILE_DEFINITIONS})
+ cotire_add_compile_flags_to_cmd(_cmd ${_option_COMPILE_FLAGS})
+ cotire_add_includes_to_cmd(_cmd "${_option_LANGUAGE}" ${_option_INCLUDE_DIRECTORIES})
+ cotire_add_makedep_flags("${_option_LANGUAGE}" "${_option_COMPILER_ID}" "${_option_COMPILER_VERSION}" _cmd)
+ # only consider existing source files for scanning
+ set (_existingSourceFiles "")
+ foreach (_sourceFile ${_sourceFiles})
+ if (EXISTS "${_sourceFile}")
+ list (APPEND _existingSourceFiles "${_sourceFile}")
+ endif()
+ endforeach()
+ if (NOT _existingSourceFiles)
+ set (${_includesVar} "" PARENT_SCOPE)
+ return()
+ endif()
+ list (APPEND _cmd ${_existingSourceFiles})
+ if (COTIRE_VERBOSE)
+ message (STATUS "execute_process: ${_cmd}")
+ endif()
+ if (_option_COMPILER_ID MATCHES "MSVC")
+ if (COTIRE_DEBUG)
+ message (STATUS "clearing VS_UNICODE_OUTPUT")
+ endif()
+ # cl.exe messes with the output streams unless the environment variable VS_UNICODE_OUTPUT is cleared
+ unset (ENV{VS_UNICODE_OUTPUT})
+ endif()
+ execute_process(COMMAND ${_cmd} WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+ RESULT_VARIABLE _result OUTPUT_QUIET ERROR_VARIABLE _output)
+ if (_result)
+ message (STATUS "Result ${_result} scanning includes of ${_existingSourceFiles}.")
+ endif()
+ cotire_parse_includes(
+ "${_option_LANGUAGE}" "${_output}"
+ "${_option_IGNORE_PATH}" "${_option_INCLUDE_PATH}"
+ "${_option_IGNORE_EXTENSIONS}"
+ _includes _unparsedLines
+ ${_sourceFiles})
+ set (${_includesVar} ${_includes} PARENT_SCOPE)
+ if (_option_UNPARSED_LINES)
+ set (${_option_UNPARSED_LINES} ${_unparsedLines} PARENT_SCOPE)
+ endif()
+endfunction()
+
+macro (cotire_append_undefs _contentsVar)
+ set (_undefs ${ARGN})
+ if (_undefs)
+ list (REMOVE_DUPLICATES _undefs)
+ foreach (_definition ${_undefs})
+ list (APPEND ${_contentsVar} "#undef ${_definition}")
+ endforeach()
+ endif()
+endmacro()
+
+macro (cotire_comment_str _language _commentText _commentVar)
+ if ("${_language}" STREQUAL "CMAKE")
+ set (${_commentVar} "# ${_commentText}")
+ else()
+ set (${_commentVar} "/* ${_commentText} */")
+ endif()
+endmacro()
+
+function (cotire_write_file _language _file _contents _force)
+ get_filename_component(_moduleName "${COTIRE_CMAKE_MODULE_FILE}" NAME)
+ cotire_comment_str("${_language}" "${_moduleName} ${COTIRE_CMAKE_MODULE_VERSION} generated file" _header1)
+ cotire_comment_str("${_language}" "${_file}" _header2)
+ set (_contents "${_header1}\n${_header2}\n${_contents}")
+ if (COTIRE_DEBUG)
+ message (STATUS "${_contents}")
+ endif()
+ if (_force OR NOT EXISTS "${_file}")
+ file (WRITE "${_file}" "${_contents}")
+ else()
+ file (READ "${_file}" _oldContents)
+ if (NOT "${_oldContents}" STREQUAL "${_contents}")
+ file (WRITE "${_file}" "${_contents}")
+ else()
+ if (COTIRE_DEBUG)
+ message (STATUS "${_file} unchanged")
+ endif()
+ endif()
+ endif()
+endfunction()
+
+function (cotire_generate_unity_source _unityFile)
+ set(_options "")
+ set(_oneValueArgs LANGUAGE)
+ set(_multiValueArgs
+ DEPENDS SOURCES_COMPILE_DEFINITIONS
+ PRE_UNDEFS SOURCES_PRE_UNDEFS POST_UNDEFS SOURCES_POST_UNDEFS PROLOGUE EPILOGUE)
+ cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
+ if (_option_DEPENDS)
+ cotire_check_file_up_to_date(_unityFileIsUpToDate "${_unityFile}" ${_option_DEPENDS})
+ if (_unityFileIsUpToDate)
+ return()
+ endif()
+ endif()
+ set (_sourceFiles ${_option_UNPARSED_ARGUMENTS})
+ if (NOT _option_PRE_UNDEFS)
+ set (_option_PRE_UNDEFS "")
+ endif()
+ if (NOT _option_SOURCES_PRE_UNDEFS)
+ set (_option_SOURCES_PRE_UNDEFS "")
+ endif()
+ if (NOT _option_POST_UNDEFS)
+ set (_option_POST_UNDEFS "")
+ endif()
+ if (NOT _option_SOURCES_POST_UNDEFS)
+ set (_option_SOURCES_POST_UNDEFS "")
+ endif()
+ set (_contents "")
+ if (_option_PROLOGUE)
+ list (APPEND _contents ${_option_PROLOGUE})
+ endif()
+ if (_option_LANGUAGE AND _sourceFiles)
+ if ("${_option_LANGUAGE}" STREQUAL "CXX")
+ list (APPEND _contents "#ifdef __cplusplus")
+ elseif ("${_option_LANGUAGE}" STREQUAL "C")
+ list (APPEND _contents "#ifndef __cplusplus")
+ endif()
+ endif()
+ set (_compileUndefinitions "")
+ foreach (_sourceFile ${_sourceFiles})
+ cotire_get_source_compile_definitions(
+ "${_option_CONFIGURATION}" "${_option_LANGUAGE}" "${_sourceFile}" _compileDefinitions
+ ${_option_SOURCES_COMPILE_DEFINITIONS})
+ cotire_get_source_undefs("${_sourceFile}" COTIRE_UNITY_SOURCE_PRE_UNDEFS _sourcePreUndefs ${_option_SOURCES_PRE_UNDEFS})
+ cotire_get_source_undefs("${_sourceFile}" COTIRE_UNITY_SOURCE_POST_UNDEFS _sourcePostUndefs ${_option_SOURCES_POST_UNDEFS})
+ if (_option_PRE_UNDEFS)
+ list (APPEND _compileUndefinitions ${_option_PRE_UNDEFS})
+ endif()
+ if (_sourcePreUndefs)
+ list (APPEND _compileUndefinitions ${_sourcePreUndefs})
+ endif()
+ if (_compileUndefinitions)
+ cotire_append_undefs(_contents ${_compileUndefinitions})
+ set (_compileUndefinitions "")
+ endif()
+ if (_sourcePostUndefs)
+ list (APPEND _compileUndefinitions ${_sourcePostUndefs})
+ endif()
+ if (_option_POST_UNDEFS)
+ list (APPEND _compileUndefinitions ${_option_POST_UNDEFS})
+ endif()
+ foreach (_definition ${_compileDefinitions})
+ if ("${_definition}" MATCHES "^([a-zA-Z0-9_]+)=(.+)$")
+ list (APPEND _contents "#define ${CMAKE_MATCH_1} ${CMAKE_MATCH_2}")
+ list (INSERT _compileUndefinitions 0 "${CMAKE_MATCH_1}")
+ else()
+ list (APPEND _contents "#define ${_definition}")
+ list (INSERT _compileUndefinitions 0 "${_definition}")
+ endif()
+ endforeach()
+ get_filename_component(_sourceFile "${_sourceFile}" ABSOLUTE)
+ if (WIN32)
+ file (TO_NATIVE_PATH "${_sourceFile}" _sourceFile)
+ endif()
+ list (APPEND _contents "#include \"${_sourceFile}\"")
+ endforeach()
+ if (_compileUndefinitions)
+ cotire_append_undefs(_contents ${_compileUndefinitions})
+ set (_compileUndefinitions "")
+ endif()
+ if (_option_LANGUAGE AND _sourceFiles)
+ list (APPEND _contents "#endif")
+ endif()
+ if (_option_EPILOGUE)
+ list (APPEND _contents ${_option_EPILOGUE})
+ endif()
+ list (APPEND _contents "")
+ string (REPLACE ";" "\n" _contents "${_contents}")
+ if (COTIRE_VERBOSE)
+ message ("${_contents}")
+ endif()
+ cotire_write_file("${_option_LANGUAGE}" "${_unityFile}" "${_contents}" TRUE)
+endfunction()
+
+function (cotire_generate_prefix_header _prefixFile)
+ set(_options "")
+ set(_oneValueArgs LANGUAGE COMPILER_EXECUTABLE COMPILER_ID COMPILER_VERSION)
+ set(_multiValueArgs DEPENDS COMPILE_DEFINITIONS COMPILE_FLAGS
+ INCLUDE_DIRECTORIES IGNORE_PATH INCLUDE_PATH IGNORE_EXTENSIONS)
+ cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
+ if (_option_DEPENDS)
+ cotire_check_file_up_to_date(_prefixFileIsUpToDate "${_prefixFile}" ${_option_DEPENDS})
+ if (_prefixFileIsUpToDate)
+ return()
+ endif()
+ endif()
+ set (_epilogue "")
+ if (_option_COMPILER_ID MATCHES "Intel")
+ # Intel compiler requires hdrstop pragma to stop generating PCH file
+ set (_epilogue "#pragma hdrstop")
+ endif()
+ set (_sourceFiles ${_option_UNPARSED_ARGUMENTS})
+ cotire_scan_includes(_selectedHeaders ${_sourceFiles}
+ LANGUAGE "${_option_LANGUAGE}"
+ COMPILER_EXECUTABLE "${_option_COMPILER_EXECUTABLE}"
+ COMPILER_ID "${_option_COMPILER_ID}"
+ COMPILER_VERSION "${_option_COMPILER_VERSION}"
+ COMPILE_DEFINITIONS ${_option_COMPILE_DEFINITIONS}
+ COMPILE_FLAGS ${_option_COMPILE_FLAGS}
+ INCLUDE_DIRECTORIES ${_option_INCLUDE_DIRECTORIES}
+ IGNORE_PATH ${_option_IGNORE_PATH}
+ INCLUDE_PATH ${_option_INCLUDE_PATH}
+ IGNORE_EXTENSIONS ${_option_IGNORE_EXTENSIONS}
+ UNPARSED_LINES _unparsedLines)
+ cotire_generate_unity_source("${_prefixFile}" EPILOGUE ${_epilogue} LANGUAGE "${_option_LANGUAGE}" ${_selectedHeaders})
+ set (_unparsedLinesFile "${_prefixFile}.log")
+ if (_unparsedLines)
+ if (COTIRE_VERBOSE OR NOT _selectedHeaders)
+ list (LENGTH _unparsedLines _skippedLineCount)
+ file (RELATIVE_PATH _unparsedLinesFileRelPath "${CMAKE_BINARY_DIR}" "${_unparsedLinesFile}")
+ message (STATUS "${_skippedLineCount} line(s) skipped, see ${_unparsedLinesFileRelPath}")
+ endif()
+ string (REPLACE ";" "\n" _unparsedLines "${_unparsedLines}")
+ endif()
+ file (WRITE "${_unparsedLinesFile}" "${_unparsedLines}\n")
+endfunction()
+
+function (cotire_add_makedep_flags _language _compilerID _compilerVersion _flagsVar)
+ set (_flags ${${_flagsVar}})
+ if (_compilerID MATCHES "MSVC")
+ # cl.exe options used
+ # /nologo suppresses display of sign-on banner
+ # /TC treat all files named on the command line as C source files
+ # /TP treat all files named on the command line as C++ source files
+ # /EP preprocess to stdout without #line directives
+ # /showIncludes list include files
+ set (_sourceFileTypeC "/TC")
+ set (_sourceFileTypeCXX "/TP")
+ if (_flags)
+ # append to list
+ list (APPEND _flags /nologo "${_sourceFileType${_language}}" /EP /showIncludes)
+ else()
+ # return as a flag string
+ set (_flags "${_sourceFileType${_language}} /EP /showIncludes")
+ endif()
+ elseif (_compilerID MATCHES "GNU")
+ # GCC options used
+ # -H print the name of each header file used
+ # -E invoke preprocessor
+ # -fdirectives-only do not expand macros, requires GCC >= 4.3
+ if (_flags)
+ # append to list
+ list (APPEND _flags -H -E)
+ if (NOT "${_compilerVersion}" VERSION_LESS "4.3.0")
+ list (APPEND _flags "-fdirectives-only")
+ endif()
+ else()
+ # return as a flag string
+ set (_flags "-H -E")
+ if (NOT "${_compilerVersion}" VERSION_LESS "4.3.0")
+ set (_flags "${_flags} -fdirectives-only")
+ endif()
+ endif()
+ elseif (_compilerID MATCHES "Clang")
+ # Clang options used
+ # -H print the name of each header file used
+ # -E invoke preprocessor
+ if (_flags)
+ # append to list
+ list (APPEND _flags -H -E)
+ else()
+ # return as a flag string
+ set (_flags "-H -E")
+ endif()
+ elseif (_compilerID MATCHES "Intel")
+ if (WIN32)
+ # Windows Intel options used
+ # /nologo do not display compiler version information
+ # /QH display the include file order
+ # /EP preprocess to stdout, omitting #line directives
+ # /TC process all source or unrecognized file types as C source files
+ # /TP process all source or unrecognized file types as C++ source files
+ set (_sourceFileTypeC "/TC")
+ set (_sourceFileTypeCXX "/TP")
+ if (_flags)
+ # append to list
+ list (APPEND _flags /nologo "${_sourceFileType${_language}}" /EP /QH)
+ else()
+ # return as a flag string
+ set (_flags "${_sourceFileType${_language}} /EP /QH")
+ endif()
+ else()
+ # Linux / Mac OS X Intel options used
+ # -H print the name of each header file used
+ # -EP preprocess to stdout, omitting #line directives
+ # -Kc++ process all source or unrecognized file types as C++ source files
+ if (_flags)
+ # append to list
+ if ("${_language}" STREQUAL "CXX")
+ list (APPEND _flags -Kc++)
+ endif()
+ list (APPEND _flags -H -EP)
+ else()
+ # return as a flag string
+ if ("${_language}" STREQUAL "CXX")
+ set (_flags "-Kc++ ")
+ endif()
+ set (_flags "${_flags}-H -EP")
+ endif()
+ endif()
+ else()
+ message (FATAL_ERROR "Unsupported ${_language} compiler ${_compilerID} version ${_compilerVersion}.")
+ endif()
+ set (${_flagsVar} ${_flags} PARENT_SCOPE)
+endfunction()
+
+function (cotire_add_pch_compilation_flags _language _compilerID _compilerVersion _prefixFile _pchFile _hostFile _flagsVar)
+ set (_flags ${${_flagsVar}})
+ if (_compilerID MATCHES "MSVC")
+ file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative)
+ file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative)
+ file (TO_NATIVE_PATH "${_hostFile}" _hostFileNative)
+ # cl.exe options used
+ # /Yc creates a precompiled header file
+ # /Fp specifies precompiled header binary file name
+ # /FI forces inclusion of file
+ # /TC treat all files named on the command line as C source files
+ # /TP treat all files named on the command line as C++ source files
+ # /Zs syntax check only
+ set (_sourceFileTypeC "/TC")
+ set (_sourceFileTypeCXX "/TP")
+ if (_flags)
+ # append to list
+ list (APPEND _flags /nologo "${_sourceFileType${_language}}"
+ "/Yc${_prefixFileNative}" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}" /Zs "${_hostFileNative}")
+ else()
+ # return as a flag string
+ set (_flags "/Yc\"${_prefixFileNative}\" /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"")
+ endif()
+ elseif (_compilerID MATCHES "GNU|Clang")
+ # GCC / Clang options used
+ # -x specify the source language
+ # -c compile but do not link
+ # -o place output in file
+ set (_xLanguage_C "c-header")
+ set (_xLanguage_CXX "c++-header")
+ if (_flags)
+ # append to list
+ list (APPEND _flags "-x" "${_xLanguage_${_language}}" "-c" "${_prefixFile}" -o "${_pchFile}")
+ else()
+ # return as a flag string
+ set (_flags "-x ${_xLanguage_${_language}} -c \"${_prefixFile}\" -o \"${_pchFile}\"")
+ endif()
+ elseif (_compilerID MATCHES "Intel")
+ if (WIN32)
+ file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative)
+ file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative)
+ file (TO_NATIVE_PATH "${_hostFile}" _hostFileNative)
+ # Windows Intel options used
+ # /nologo do not display compiler version information
+ # /Yc create a precompiled header (PCH) file
+ # /Fp specify a path or file name for precompiled header files
+ # /FI tells the preprocessor to include a specified file name as the header file
+ # /TC process all source or unrecognized file types as C source files
+ # /TP process all source or unrecognized file types as C++ source files
+ # /Zs syntax check only
+ # /Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2)
+ set (_sourceFileTypeC "/TC")
+ set (_sourceFileTypeCXX "/TP")
+ if (_flags)
+ # append to list
+ list (APPEND _flags /nologo "${_sourceFileType${_language}}"
+ "/Yc" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}" /Zs "${_hostFileNative}")
+ if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
+ list (APPEND _flags "/Wpch-messages")
+ endif()
+ else()
+ # return as a flag string
+ set (_flags "/Yc /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"")
+ if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
+ set (_flags "${_flags} /Wpch-messages")
+ endif()
+ endif()
+ else()
+ # Linux / Mac OS X Intel options used
+ # -pch-dir location for precompiled header files
+ # -pch-create name of the precompiled header (PCH) to create
+ # -Kc++ process all source or unrecognized file types as C++ source files
+ # -fsyntax-only check only for correct syntax
+ # -Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2)
+ get_filename_component(_pchDir "${_pchFile}" PATH)
+ get_filename_component(_pchName "${_pchFile}" NAME)
+ set (_xLanguage_C "c-header")
+ set (_xLanguage_CXX "c++-header")
+ if (_flags)
+ # append to list
+ if ("${_language}" STREQUAL "CXX")
+ list (APPEND _flags -Kc++)
+ endif()
+ list (APPEND _flags "-include" "${_prefixFile}" "-pch-dir" "${_pchDir}" "-pch-create" "${_pchName}" "-fsyntax-only" "${_hostFile}")
+ if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
+ list (APPEND _flags "-Wpch-messages")
+ endif()
+ else()
+ # return as a flag string
+ set (_flags "-include \"${_prefixFile}\" -pch-dir \"${_pchDir}\" -pch-create \"${_pchName}\"")
+ if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
+ set (_flags "${_flags} -Wpch-messages")
+ endif()
+ endif()
+ endif()
+ else()
+ message (FATAL_ERROR "Unsupported ${_language} compiler ${_compilerID} version ${_compilerVersion}.")
+ endif()
+ set (${_flagsVar} ${_flags} PARENT_SCOPE)
+endfunction()
+
+function (cotire_add_prefix_pch_inclusion_flags _language _compilerID _compilerVersion _prefixFile _pchFile _flagsVar)
+ set (_flags ${${_flagsVar}})
+ if (_compilerID MATCHES "MSVC")
+ file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative)
+ # cl.exe options used
+ # /Yu uses a precompiled header file during build
+ # /Fp specifies precompiled header binary file name
+ # /FI forces inclusion of file
+ if (_pchFile)
+ file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative)
+ if (_flags)
+ # append to list
+ list (APPEND _flags "/Yu${_prefixFileNative}" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}")
+ else()
+ # return as a flag string
+ set (_flags "/Yu\"${_prefixFileNative}\" /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"")
+ endif()
+ else()
+ # no precompiled header, force inclusion of prefix header
+ if (_flags)
+ # append to list
+ list (APPEND _flags "/FI${_prefixFileNative}")
+ else()
+ # return as a flag string
+ set (_flags "/FI\"${_prefixFileNative}\"")
+ endif()
+ endif()
+ elseif (_compilerID MATCHES "GNU")
+ # GCC options used
+ # -include process include file as the first line of the primary source file
+ # -Winvalid-pch warns if precompiled header is found but cannot be used
+ if (_flags)
+ # append to list
+ list (APPEND _flags "-include" "${_prefixFile}" "-Winvalid-pch")
+ else()
+ # return as a flag string
+ set (_flags "-include \"${_prefixFile}\" -Winvalid-pch")
+ endif()
+ elseif (_compilerID MATCHES "Clang")
+ # Clang options used
+ # -include process include file as the first line of the primary source file
+ # -Qunused-arguments don't emit warning for unused driver arguments
+ if (_flags)
+ # append to list
+ list (APPEND _flags "-include" "${_prefixFile}" "-Qunused-arguments")
+ else()
+ # return as a flag string
+ set (_flags "-include \"${_prefixFile}\" -Qunused-arguments")
+ endif()
+ elseif (_compilerID MATCHES "Intel")
+ if (WIN32)
+ file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative)
+ # Windows Intel options used
+ # /Yu use a precompiled header (PCH) file
+ # /Fp specify a path or file name for precompiled header files
+ # /FI tells the preprocessor to include a specified file name as the header file
+ # /Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2)
+ if (_pchFile)
+ file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative)
+ if (_flags)
+ # append to list
+ list (APPEND _flags "/Yu" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}")
+ if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
+ list (APPEND _flags "/Wpch-messages")
+ endif()
+ else()
+ # return as a flag string
+ set (_flags "/Yu /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"")
+ if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
+ set (_flags "${_flags} /Wpch-messages")
+ endif()
+ endif()
+ else()
+ # no precompiled header, force inclusion of prefix header
+ if (_flags)
+ # append to list
+ list (APPEND _flags "/FI${_prefixFileNative}")
+ else()
+ # return as a flag string
+ set (_flags "/FI\"${_prefixFileNative}\"")
+ endif()
+ endif()
+ else()
+ # Linux / Mac OS X Intel options used
+ # -pch-dir location for precompiled header files
+ # -pch-use name of the precompiled header (PCH) to use
+ # -include process include file as the first line of the primary source file
+ # -Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2)
+ if (_pchFile)
+ get_filename_component(_pchDir "${_pchFile}" PATH)
+ get_filename_component(_pchName "${_pchFile}" NAME)
+ if (_flags)
+ # append to list
+ list (APPEND _flags "-include" "${_prefixFile}" "-pch-dir" "${_pchDir}" "-pch-use" "${_pchName}")
+ if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
+ list (APPEND _flags "-Wpch-messages")
+ endif()
+ else()
+ # return as a flag string
+ set (_flags "-include \"${_prefixFile}\" -pch-dir \"${_pchDir}\" -pch-use \"${_pchName}\"")
+ if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
+ set (_flags "${_flags} -Wpch-messages")
+ endif()
+ endif()
+ else()
+ # no precompiled header, force inclusion of prefix header
+ if (_flags)
+ # append to list
+ list (APPEND _flags "-include" "${_prefixFile}")
+ else()
+ # return as a flag string
+ set (_flags "-include \"${_prefixFile}\"")
+ endif()
+ endif()
+ endif()
+ else()
+ message (FATAL_ERROR "Unsupported ${_language} compiler ${_compilerID} version ${_compilerVersion}.")
+ endif()
+ set (${_flagsVar} ${_flags} PARENT_SCOPE)
+endfunction()
+
+function (cotire_precompile_prefix_header _prefixFile _pchFile _hostFile)
+ set(_options "")
+ set(_oneValueArgs COMPILER_EXECUTABLE COMPILER_ID COMPILER_VERSION LANGUAGE)
+ set(_multiValueArgs COMPILE_DEFINITIONS COMPILE_FLAGS INCLUDE_DIRECTORIES)
+ cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
+ if (NOT _option_LANGUAGE)
+ set (_option_LANGUAGE "CXX")
+ endif()
+ if (NOT _option_COMPILER_ID)
+ set (_option_COMPILER_ID "${CMAKE_${_option_LANGUAGE}_ID}")
+ endif()
+ cotire_init_compile_cmd(_cmd "${_option_LANGUAGE}" "${_option_COMPILER_EXECUTABLE}" "${_option_COMPILER_ARG1}")
+ cotire_add_definitions_to_cmd(_cmd "${_option_LANGUAGE}" ${_option_COMPILE_DEFINITIONS})
+ cotire_add_compile_flags_to_cmd(_cmd ${_option_COMPILE_FLAGS})
+ cotire_add_includes_to_cmd(_cmd "${_option_LANGUAGE}" ${_option_INCLUDE_DIRECTORIES})
+ cotire_add_pch_compilation_flags(
+ "${_option_LANGUAGE}" "${_option_COMPILER_ID}" "${_option_COMPILER_VERSION}"
+ "${_prefixFile}" "${_pchFile}" "${_hostFile}" _cmd)
+ if (COTIRE_VERBOSE)
+ message (STATUS "execute_process: ${_cmd}")
+ endif()
+ if (_option_COMPILER_ID MATCHES "MSVC")
+ if (COTIRE_DEBUG)
+ message (STATUS "clearing VS_UNICODE_OUTPUT")
+ endif()
+ # cl.exe messes with the output streams unless the environment variable VS_UNICODE_OUTPUT is cleared
+ unset (ENV{VS_UNICODE_OUTPUT})
+ endif()
+ execute_process(COMMAND ${_cmd} WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" RESULT_VARIABLE _result)
+ if (_result)
+ message (FATAL_ERROR "Error ${_result} precompiling ${_prefixFile}.")
+ endif()
+endfunction()
+
+function (cotire_check_precompiled_header_support _language _targetSourceDir _target _msgVar)
+ set (_unsupportedCompiler
+ "Precompiled headers not supported for ${_language} compiler ${CMAKE_${_language}_COMPILER_ID}")
+ if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC")
+ # supported since Visual Studio C++ 6.0
+ # and CMake does not support an earlier version
+ set (${_msgVar} "" PARENT_SCOPE)
+ elseif (CMAKE_${_language}_COMPILER_ID MATCHES "GNU")
+ # GCC PCH support requires version >= 3.4
+ cotire_determine_compiler_version("${_language}" COTIRE_${_language}_COMPILER)
+ if ("${COTIRE_${_language}_COMPILER_VERSION}" MATCHES ".+" AND
+ "${COTIRE_${_language}_COMPILER_VERSION}" VERSION_LESS "3.4.0")
+ set (${_msgVar} "${_unsupportedCompiler} version ${COTIRE_${_language}_COMPILER_VERSION}." PARENT_SCOPE)
+ else()
+ set (${_msgVar} "" PARENT_SCOPE)
+ endif()
+ elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Clang")
+ # all Clang versions have PCH support
+ set (${_msgVar} "" PARENT_SCOPE)
+ elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Intel")
+ # Intel PCH support requires version >= 8.0.0
+ cotire_determine_compiler_version("${_language}" COTIRE_${_language}_COMPILER)
+ if ("${COTIRE_${_language}_COMPILER_VERSION}" MATCHES ".+" AND
+ "${COTIRE_${_language}_COMPILER_VERSION}" VERSION_LESS "8.0.0")
+ set (${_msgVar} "${_unsupportedCompiler} version ${COTIRE_${_language}_COMPILER_VERSION}." PARENT_SCOPE)
+ else()
+ set (${_msgVar} "" PARENT_SCOPE)
+ endif()
+ else()
+ set (${_msgVar} "${_unsupportedCompiler}." PARENT_SCOPE)
+ endif()
+ if (APPLE)
+ # PCH compilation not supported by GCC / Clang for multi-architecture builds (e.g., i386, x86_64)
+ if (CMAKE_CONFIGURATION_TYPES)
+ set (_configs ${CMAKE_CONFIGURATION_TYPES})
+ elseif (CMAKE_BUILD_TYPE)
+ set (_configs ${CMAKE_BUILD_TYPE})
+ else()
+ set (_configs "None")
+ endif()
+ foreach (_config ${_configs})
+ set (_targetFlags "")
+ cotire_get_target_compile_flags("${_config}" "${_language}" "${_targetSourceDir}" "${_target}" _targetFlags)
+ cotire_filter_compile_flags("${_language}" "arch" _architectures _ignore ${_targetFlags})
+ list (LENGTH _architectures _numberOfArchitectures)
+ if (_numberOfArchitectures GREATER 1)
+ string (REPLACE ";" ", " _architectureStr "${_architectures}")
+ set (${_msgVar}
+ "Precompiled headers not supported on Darwin for multi-architecture builds (${_architectureStr})."
+ PARENT_SCOPE)
+ break()
+ endif()
+ endforeach()
+ endif()
+endfunction()
+
+macro (cotire_get_intermediate_dir _cotireDir)
+ get_filename_component(${_cotireDir} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${COTIRE_INTDIR}" ABSOLUTE)
+endmacro()
+
+macro (cotire_setup_file_extension_variables)
+ set (_unityFileExt_C ".c")
+ set (_unityFileExt_CXX ".cxx")
+ set (_prefixFileExt_C ".h")
+ set (_prefixFileExt_CXX ".hxx")
+endmacro()
+
+function (cotire_make_single_unity_source_file_path _language _target _unityFileVar)
+ cotire_setup_file_extension_variables()
+ if (NOT DEFINED _unityFileExt_${_language})
+ set (${_unityFileVar} "" PARENT_SCOPE)
+ return()
+ endif()
+ set (_unityFileBaseName "${_target}_${_language}${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}")
+ set (_unityFileName "${_unityFileBaseName}${_unityFileExt_${_language}}")
+ cotire_get_intermediate_dir(_baseDir)
+ set (_unityFile "${_baseDir}/${_unityFileName}")
+ set (${_unityFileVar} "${_unityFile}" PARENT_SCOPE)
+ if (COTIRE_DEBUG)
+ message(STATUS "${_unityFile}")
+ endif()
+endfunction()
+
+function (cotire_make_unity_source_file_paths _language _target _maxIncludes _unityFilesVar)
+ cotire_setup_file_extension_variables()
+ if (NOT DEFINED _unityFileExt_${_language})
+ set (${_unityFileVar} "" PARENT_SCOPE)
+ return()
+ endif()
+ set (_unityFileBaseName "${_target}_${_language}${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}")
+ cotire_get_intermediate_dir(_baseDir)
+ set (_startIndex 0)
+ set (_index 0)
+ set (_unityFiles "")
+ set (_sourceFiles ${ARGN})
+ foreach (_sourceFile ${_sourceFiles})
+ get_source_file_property(_startNew "${_sourceFile}" COTIRE_START_NEW_UNITY_SOURCE)
+ math (EXPR _unityFileCount "${_index} - ${_startIndex}")
+ if (_startNew OR (_maxIncludes GREATER 0 AND NOT _unityFileCount LESS _maxIncludes))
+ if (_index GREATER 0)
+ # start new unity file segment
+ math (EXPR _endIndex "${_index} - 1")
+ set (_unityFileName "${_unityFileBaseName}_${_startIndex}_${_endIndex}${_unityFileExt_${_language}}")
+ list (APPEND _unityFiles "${_baseDir}/${_unityFileName}")
+ endif()
+ set (_startIndex ${_index})
+ endif()
+ math (EXPR _index "${_index} + 1")
+ endforeach()
+ list (LENGTH _sourceFiles _numberOfSources)
+ if (_startIndex EQUAL 0)
+ # there is only a single unity file
+ cotire_make_single_unity_source_file_path(${_language} ${_target} _unityFiles)
+ elseif (_startIndex LESS _numberOfSources)
+ # end with final unity file segment
+ math (EXPR _endIndex "${_index} - 1")
+ set (_unityFileName "${_unityFileBaseName}_${_startIndex}_${_endIndex}${_unityFileExt_${_language}}")
+ list (APPEND _unityFiles "${_baseDir}/${_unityFileName}")
+ endif()
+ set (${_unityFilesVar} ${_unityFiles} PARENT_SCOPE)
+ if (COTIRE_DEBUG)
+ message(STATUS "${_unityFiles}")
+ endif()
+endfunction()
+
+function (cotire_unity_to_prefix_file_path _language _target _unityFile _prefixFileVar)
+ cotire_setup_file_extension_variables()
+ if (NOT DEFINED _unityFileExt_${_language})
+ set (${_prefixFileVar} "" PARENT_SCOPE)
+ return()
+ endif()
+ set (_unityFileBaseName "${_target}_${_language}${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}")
+ set (_prefixFileBaseName "${_target}_${_language}${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}")
+ string (REPLACE "${_unityFileBaseName}" "${_prefixFileBaseName}" _prefixFile "${_unityFile}")
+ string (REGEX REPLACE "${_unityFileExt_${_language}}$" "${_prefixFileExt_${_language}}" _prefixFile "${_prefixFile}")
+ set (${_prefixFileVar} "${_prefixFile}" PARENT_SCOPE)
+endfunction()
+
+function (cotire_make_prefix_file_name _language _target _prefixFileBaseNameVar _prefixFileNameVar)
+ cotire_setup_file_extension_variables()
+ if (NOT _language)
+ set (_prefixFileBaseName "${_target}${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}")
+ set (_prefixFileName "${_prefixFileBaseName}${_prefixFileExt_C}")
+ elseif (DEFINED _prefixFileExt_${_language})
+ set (_prefixFileBaseName "${_target}_${_language}${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}")
+ set (_prefixFileName "${_prefixFileBaseName}${_prefixFileExt_${_language}}")
+ else()
+ set (_prefixFileBaseName "")
+ set (_prefixFileName "")
+ endif()
+ set (${_prefixFileBaseNameVar} "${_prefixFileBaseName}" PARENT_SCOPE)
+ set (${_prefixFileNameVar} "${_prefixFileName}" PARENT_SCOPE)
+endfunction()
+
+function (cotire_make_prefix_file_path _language _target _prefixFileVar)
+ cotire_make_prefix_file_name("${_language}" "${_target}" _prefixFileBaseName _prefixFileName)
+ set (${_prefixFileVar} "" PARENT_SCOPE)
+ if (_prefixFileName)
+ if (NOT _language)
+ set (_language "C")
+ endif()
+ if (MSVC OR CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang|Intel")
+ cotire_get_intermediate_dir(_baseDir)
+ set (${_prefixFileVar} "${_baseDir}/${_prefixFileName}" PARENT_SCOPE)
+ endif()
+ endif()
+endfunction()
+
+function (cotire_make_pch_file_path _language _targetSourceDir _target _pchFileVar)
+ cotire_make_prefix_file_name("${_language}" "${_target}" _prefixFileBaseName _prefixFileName)
+ set (${_pchFileVar} "" PARENT_SCOPE)
+ if (_prefixFileBaseName AND _prefixFileName)
+ cotire_check_precompiled_header_support("${_language}" "${_targetSourceDir}" "${_target}" _msg)
+ if (NOT _msg)
+ if (XCODE)
+ # For Xcode, we completely hand off the compilation of the prefix header to the IDE
+ return()
+ endif()
+ cotire_get_intermediate_dir(_baseDir)
+ if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC")
+ # MSVC uses the extension .pch added to the prefix header base name
+ set (${_pchFileVar} "${_baseDir}/${_prefixFileBaseName}.pch" PARENT_SCOPE)
+ elseif (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang")
+ # GCC / Clang look for a precompiled header corresponding to the prefix header with the extension .gch appended
+ set (${_pchFileVar} "${_baseDir}/${_prefixFileName}.gch" PARENT_SCOPE)
+ elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Intel")
+ # Intel uses the extension .pchi added to the prefix header base name
+ set (${_pchFileVar} "${_baseDir}/${_prefixFileBaseName}.pchi" PARENT_SCOPE)
+ endif()
+ endif()
+ endif()
+endfunction()
+
+function (cotire_select_unity_source_files _unityFile _sourcesVar)
+ set (_sourceFiles ${ARGN})
+ if (_sourceFiles AND "${_unityFile}" MATCHES "${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}_([0-9]+)_([0-9]+)")
+ set (_startIndex ${CMAKE_MATCH_1})
+ set (_endIndex ${CMAKE_MATCH_2})
+ list (LENGTH _sourceFiles _numberOfSources)
+ if (NOT _startIndex LESS _numberOfSources)
+ math (EXPR _startIndex "${_numberOfSources} - 1")
+ endif()
+ if (NOT _endIndex LESS _numberOfSources)
+ math (EXPR _endIndex "${_numberOfSources} - 1")
+ endif()
+ set (_files "")
+ foreach (_index RANGE ${_startIndex} ${_endIndex})
+ list (GET _sourceFiles ${_index} _file)
+ list (APPEND _files "${_file}")
+ endforeach()
+ else()
+ set (_files ${_sourceFiles})
+ endif()
+ set (${_sourcesVar} ${_files} PARENT_SCOPE)
+endfunction()
+
+function (cotire_get_unity_source_dependencies _language _target _dependencySourcesVar)
+ set (_dependencySources "")
+ # depend on target's generated source files
+ cotire_get_objects_with_property_on(_generatedSources GENERATED SOURCE ${ARGN})
+ if (_generatedSources)
+ # but omit all generated source files that have the COTIRE_EXCLUDED property set to true
+ cotire_get_objects_with_property_on(_excludedGeneratedSources COTIRE_EXCLUDED SOURCE ${_generatedSources})
+ if (_excludedGeneratedSources)
+ list (REMOVE_ITEM _generatedSources ${_excludedGeneratedSources})
+ endif()
+ # and omit all generated source files that have the COTIRE_DEPENDENCY property set to false explicitly
+ cotire_get_objects_with_property_off(_excludedNonDependencySources COTIRE_DEPENDENCY SOURCE ${_generatedSources})
+ if (_excludedNonDependencySources)
+ list (REMOVE_ITEM _generatedSources ${_excludedNonDependencySources})
+ endif()
+ if (_generatedSources)
+ list (APPEND _dependencySources ${_generatedSources})
+ endif()
+ endif()
+ if (COTIRE_DEBUG AND _dependencySources)
+ message (STATUS "${_language} ${_target} unity source depends on ${_dependencySources}")
+ endif()
+ set (${_dependencySourcesVar} ${_dependencySources} PARENT_SCOPE)
+endfunction()
+
+function (cotire_get_prefix_header_dependencies _language _target _dependencySourcesVar)
+ # depend on target source files marked with custom COTIRE_DEPENDENCY property
+ set (_dependencySources "")
+ cotire_get_objects_with_property_on(_dependencySources COTIRE_DEPENDENCY SOURCE ${ARGN})
+ if (COTIRE_DEBUG AND _dependencySources)
+ message (STATUS "${_language} ${_target} prefix header DEPENDS ${_dependencySources}")
+ endif()
+ set (${_dependencySourcesVar} ${_dependencySources} PARENT_SCOPE)
+endfunction()
+
+function (cotire_generate_target_script _language _configurations _targetSourceDir _targetBinaryDir _target _targetScriptVar)
+ set (COTIRE_TARGET_SOURCES ${ARGN})
+ get_filename_component(_moduleName "${COTIRE_CMAKE_MODULE_FILE}" NAME)
+ set (_targetCotireScript "${CMAKE_CURRENT_BINARY_DIR}/${_target}_${_language}_${_moduleName}")
+ cotire_get_prefix_header_dependencies(${_language} ${_target} COTIRE_TARGET_PREFIX_DEPENDS ${COTIRE_TARGET_SOURCES})
+ cotire_get_unity_source_dependencies(${_language} ${_target} COTIRE_TARGET_UNITY_DEPENDS ${COTIRE_TARGET_SOURCES})
+ # set up variables to be configured
+ set (COTIRE_TARGET_LANGUAGE "${_language}")
+ cotire_determine_compiler_version("${COTIRE_TARGET_LANGUAGE}" COTIRE_${_language}_COMPILER)
+ get_target_property(COTIRE_TARGET_IGNORE_PATH ${_target} COTIRE_PREFIX_HEADER_IGNORE_PATH)
+ cotire_add_sys_root_paths(COTIRE_TARGET_IGNORE_PATH)
+ get_target_property(COTIRE_TARGET_INCLUDE_PATH ${_target} COTIRE_PREFIX_HEADER_INCLUDE_PATH)
+ cotire_add_sys_root_paths(COTIRE_TARGET_INCLUDE_PATH)
+ get_target_property(COTIRE_TARGET_PRE_UNDEFS ${_target} COTIRE_UNITY_SOURCE_PRE_UNDEFS)
+ get_target_property(COTIRE_TARGET_POST_UNDEFS ${_target} COTIRE_UNITY_SOURCE_POST_UNDEFS)
+ get_target_property(COTIRE_TARGET_MAXIMUM_NUMBER_OF_INCLUDES ${_target} COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES)
+ cotire_get_source_files_undefs(COTIRE_UNITY_SOURCE_PRE_UNDEFS COTIRE_TARGET_SOURCES_PRE_UNDEFS ${COTIRE_TARGET_SOURCES})
+ cotire_get_source_files_undefs(COTIRE_UNITY_SOURCE_POST_UNDEFS COTIRE_TARGET_SOURCES_POST_UNDEFS ${COTIRE_TARGET_SOURCES})
+ set (COTIRE_TARGET_CONFIGURATION_TYPES "${_configurations}")
+ foreach (_config ${_configurations})
+ string (TOUPPER "${_config}" _upperConfig)
+ cotire_get_target_include_directories(
+ "${_config}" "${_language}" "${_targetSourceDir}" "${_targetBinaryDir}" "${_target}" COTIRE_TARGET_INCLUDE_DIRECTORIES_${_upperConfig})
+ cotire_get_target_compile_definitions(
+ "${_config}" "${_language}" "${_targetSourceDir}" "${_target}" COTIRE_TARGET_COMPILE_DEFINITIONS_${_upperConfig})
+ cotire_get_target_compiler_flags(
+ "${_config}" "${_language}" "${_targetSourceDir}" "${_target}" COTIRE_TARGET_COMPILE_FLAGS_${_upperConfig})
+ cotire_get_source_files_compile_definitions(
+ "${_config}" "${_language}" COTIRE_TARGET_SOURCES_COMPILE_DEFINITIONS_${_upperConfig} ${COTIRE_TARGET_SOURCES})
+ endforeach()
+ get_cmake_property(_vars VARIABLES)
+ string (REGEX MATCHALL "COTIRE_[A-Za-z0-9_]+" _matchVars "${_vars}")
+ # remove COTIRE_VERBOSE which is passed as a CMake define on command line
+ list (REMOVE_ITEM _matchVars COTIRE_VERBOSE)
+ set (_contents "")
+ foreach (_var IN LISTS _matchVars ITEMS
+ MSVC CMAKE_GENERATOR CMAKE_BUILD_TYPE CMAKE_CONFIGURATION_TYPES
+ CMAKE_${_language}_COMPILER_ID CMAKE_${_language}_COMPILER CMAKE_${_language}_COMPILER_ARG1
+ CMAKE_${_language}_SOURCE_FILE_EXTENSIONS)
+ if (DEFINED ${_var})
+ string (REPLACE "\"" "\\\"" _value "${${_var}}")
+ set (_contents "${_contents}set (${_var} \"${_value}\")\n")
+ endif()
+ endforeach()
+ cotire_write_file("CMAKE" "${_targetCotireScript}" "${_contents}" FALSE)
+ set (${_targetScriptVar} "${_targetCotireScript}" PARENT_SCOPE)
+endfunction()
+
+function (cotire_setup_pch_file_compilation _language _target _targetSourceDir _targetScript _prefixFile _pchFile)
+ set (_sourceFiles ${ARGN})
+ if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel")
+ # for Visual Studio and Intel, we attach the precompiled header compilation to the first source file
+ # the remaining files include the precompiled header, see cotire_setup_pch_file_inclusion
+ if (_sourceFiles)
+ file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative)
+ file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative)
+ list (GET _sourceFiles 0 _hostFile)
+ set (_flags "")
+ cotire_determine_compiler_version("${_language}" COTIRE_${_language}_COMPILER)
+ cotire_add_pch_compilation_flags(
+ "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${COTIRE_${_language}_COMPILER_VERSION}"
+ "${_prefixFile}" "${_pchFile}" "${_hostFile}" _flags)
+ set_property (SOURCE ${_hostFile} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ")
+ set_property (SOURCE ${_hostFile} APPEND PROPERTY OBJECT_OUTPUTS "${_pchFile}")
+ # make first source file depend on prefix header
+ set_property (SOURCE ${_hostFile} APPEND PROPERTY OBJECT_DEPENDS "${_prefixFile}")
+ # mark first source file as cotired to prevent it from being used in another cotired target
+ set_property (SOURCE ${_hostFile} PROPERTY COTIRE_TARGET "${_target}")
+ endif()
+ elseif ("${CMAKE_GENERATOR}" MATCHES "Makefiles|Ninja")
+ # for makefile based generator, we add a custom command to precompile the prefix header
+ if (_targetScript)
+ cotire_set_cmd_to_prologue(_cmds)
+ list (GET _sourceFiles 0 _hostFile)
+ list (APPEND _cmds -P "${COTIRE_CMAKE_MODULE_FILE}" "precompile" "${_targetScript}" "${_prefixFile}" "${_pchFile}" "${_hostFile}")
+ file (RELATIVE_PATH _pchFileRelPath "${CMAKE_BINARY_DIR}" "${_pchFile}")
+ if (COTIRE_DEBUG)
+ message (STATUS "add_custom_command: OUTPUT ${_pchFile} ${_cmds} DEPENDS ${_prefixFile} IMPLICIT_DEPENDS ${_language} ${_prefixFile}")
+ endif()
+ set_property (SOURCE "${_pchFile}" PROPERTY GENERATED TRUE)
+ add_custom_command(OUTPUT "${_pchFile}"
+ COMMAND ${_cmds}
+ DEPENDS "${_prefixFile}"
+ IMPLICIT_DEPENDS ${_language} "${_prefixFile}"
+ WORKING_DIRECTORY "${_targetSourceDir}"
+ COMMENT "Building ${_language} precompiled header ${_pchFileRelPath}" VERBATIM)
+ endif()
+ endif()
+endfunction()
+
+function (cotire_setup_pch_file_inclusion _language _target _wholeTarget _prefixFile _pchFile)
+ set (_sourceFiles ${ARGN})
+ if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel")
+ # for Visual Studio and Intel, we include the precompiled header in all but the first source file
+ # the first source file does the precompiled header compilation, see cotire_setup_pch_file_compilation
+ list (LENGTH _sourceFiles _numberOfSourceFiles)
+ if (_numberOfSourceFiles GREATER 1)
+ # mark sources as cotired to prevent them from being used in another cotired target
+ set_source_files_properties(${_sourceFiles} PROPERTIES COTIRE_TARGET "${_target}")
+ list (REMOVE_AT _sourceFiles 0)
+ set (_flags "")
+ cotire_determine_compiler_version("${_language}" COTIRE_${_language}_COMPILER)
+ cotire_add_prefix_pch_inclusion_flags(
+ "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${COTIRE_${_language}_COMPILER_VERSION}"
+ "${_prefixFile}" "${_pchFile}" _flags)
+ set_property (SOURCE ${_sourceFiles} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ")
+ # make source files depend on precompiled header
+ set_property (SOURCE ${_sourceFiles} APPEND PROPERTY OBJECT_DEPENDS "${_pchFile}")
+ endif()
+ elseif ("${CMAKE_GENERATOR}" MATCHES "Makefiles|Ninja")
+ if (NOT _wholeTarget)
+ # for makefile based generator, we force the inclusion of the prefix header for a subset
+ # of the source files, if this is a multi-language target or has excluded files
+ set (_flags "")
+ cotire_determine_compiler_version("${_language}" COTIRE_${_language}_COMPILER)
+ cotire_add_prefix_pch_inclusion_flags(
+ "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${COTIRE_${_language}_COMPILER_VERSION}"
+ "${_prefixFile}" "${_pchFile}" _flags)
+ set_property (SOURCE ${_sourceFiles} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ")
+ # mark sources as cotired to prevent them from being used in another cotired target
+ set_source_files_properties(${_sourceFiles} PROPERTIES COTIRE_TARGET "${_target}")
+ endif()
+ # make source files depend on precompiled header
+ set_property (SOURCE ${_sourceFiles} APPEND PROPERTY OBJECT_DEPENDS "${_pchFile}")
+ endif()
+endfunction()
+
+function (cotire_setup_prefix_file_inclusion _language _target _prefixFile)
+ set (_sourceFiles ${ARGN})
+ # force the inclusion of the prefix header for the given source files
+ set (_flags "")
+ cotire_determine_compiler_version("${_language}" COTIRE_${_language}_COMPILER)
+ cotire_add_prefix_pch_inclusion_flags(
+ "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${COTIRE_${_language}_COMPILER_VERSION}"
+ "${_prefixFile}" "" _flags)
+ set_property (SOURCE ${_sourceFiles} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ")
+ # mark sources as cotired to prevent them from being used in another cotired target
+ set_source_files_properties(${_sourceFiles} PROPERTIES COTIRE_TARGET "${_target}")
+ # make source files depend on prefix header
+ set_property (SOURCE ${_sourceFiles} APPEND PROPERTY OBJECT_DEPENDS "${_prefixFile}")
+endfunction()
+
+function (cotire_get_first_set_property_value _propertyValueVar _type _object)
+ set (_properties ${ARGN})
+ foreach (_property ${_properties})
+ get_property(_propertyValue ${_type} "${_object}" PROPERTY ${_property})
+ if (_propertyValue)
+ set (${_propertyValueVar} ${_propertyValue} PARENT_SCOPE)
+ return()
+ endif()
+ endforeach()
+ set (${_propertyValueVar} "" PARENT_SCOPE)
+endfunction()
+
+function (cotire_setup_combine_command _language _sourceDir _targetScript _joinedFile _cmdsVar)
+ set (_files ${ARGN})
+ set (_filesPaths "")
+ foreach (_file ${_files})
+ if (IS_ABSOLUTE "${_file}")
+ set (_filePath "${_file}")
+ else()
+ get_filename_component(_filePath "${_sourceDir}/${_file}" ABSOLUTE)
+ endif()
+ file (RELATIVE_PATH _fileRelPath "${_sourceDir}" "${_filePath}")
+ if (NOT IS_ABSOLUTE "${_fileRelPath}" AND NOT "${_fileRelPath}" MATCHES "^\\.\\.")
+ list (APPEND _filesPaths "${_fileRelPath}")
+ else()
+ list (APPEND _filesPaths "${_filePath}")
+ endif()
+ endforeach()
+ cotire_set_cmd_to_prologue(_prefixCmd)
+ list (APPEND _prefixCmd -P "${COTIRE_CMAKE_MODULE_FILE}" "combine")
+ if (_targetScript)
+ list (APPEND _prefixCmd "${_targetScript}")
+ endif()
+ list (APPEND _prefixCmd "${_joinedFile}" ${_filesPaths})
+ if (COTIRE_DEBUG)
+ message (STATUS "add_custom_command: OUTPUT ${_joinedFile} COMMAND ${_prefixCmd} DEPENDS ${_files}")
+ endif()
+ set_property (SOURCE "${_joinedFile}" PROPERTY GENERATED TRUE)
+ file (RELATIVE_PATH _joinedFileRelPath "${CMAKE_BINARY_DIR}" "${_joinedFile}")
+ get_filename_component(_joinedFileName "${_joinedFileRelPath}" NAME_WE)
+ if (_language AND _joinedFileName MATCHES "${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}$")
+ set (_comment "Generating ${_language} unity source ${_joinedFileRelPath}")
+ elseif (_language AND _joinedFileName MATCHES "${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}$")
+ set (_comment "Generating ${_language} prefix header ${_joinedFileRelPath}")
+ else()
+ set (_comment "Generating ${_joinedFileRelPath}")
+ endif()
+ add_custom_command(
+ OUTPUT "${_joinedFile}"
+ COMMAND ${_prefixCmd}
+ DEPENDS ${_files}
+ COMMENT "${_comment}"
+ WORKING_DIRECTORY "${_sourceDir}" VERBATIM)
+ list (APPEND ${_cmdsVar} COMMAND ${_prefixCmd})
+ set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE)
+endfunction()
+
+function (cotire_setup_target_pch_usage _languages _targetSourceDir _target _wholeTarget)
+ if (XCODE)
+ # for Xcode, we attach a pre-build action to generate the unity sources and prefix headers
+ # if necessary, we also generate a single prefix header which includes all language specific prefix headers
+ set (_prefixFiles "")
+ foreach (_language ${_languages})
+ get_property(_prefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER)
+ if (_prefixFile)
+ list (APPEND _prefixFiles "${_prefixFile}")
+ endif()
+ endforeach()
+ set (_cmds ${ARGN})
+ list (LENGTH _prefixFiles _numberOfPrefixFiles)
+ if (_numberOfPrefixFiles GREATER 1)
+ cotire_make_prefix_file_path("" ${_target} _prefixHeader)
+ cotire_setup_combine_command("" "${_targetSourceDir}" "" "${_prefixHeader}" _cmds ${_prefixFiles})
+ else()
+ set (_prefixHeader "${_prefixFiles}")
+ endif()
+ if (COTIRE_DEBUG)
+ message (STATUS "add_custom_command: TARGET ${_target} PRE_BUILD ${_cmds}")
+ endif()
+ add_custom_command(TARGET "${_target}"
+ PRE_BUILD ${_cmds}
+ WORKING_DIRECTORY "${_targetSourceDir}"
+ COMMENT "Updating target ${_target} prefix headers" VERBATIM)
+ # make Xcode precompile the generated prefix header with ProcessPCH and ProcessPCH++
+ set_target_properties(${_target} PROPERTIES XCODE_ATTRIBUTE_GCC_PRECOMPILE_PREFIX_HEADER "YES")
+ set_target_properties(${_target} PROPERTIES XCODE_ATTRIBUTE_GCC_PREFIX_HEADER "${_prefixHeader}")
+ elseif ("${CMAKE_GENERATOR}" MATCHES "Makefiles|Ninja")
+ # for makefile based generator, we force inclusion of the prefix header for all target source files
+ # if this is a single-language target without any excluded files
+ if (_wholeTarget)
+ set (_language "${_languages}")
+ # for Visual Studio and Intel, precompiled header inclusion is always done on the source file level
+ # see cotire_setup_pch_file_inclusion
+ if (NOT CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel")
+ get_property(_prefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER)
+ get_property(_pchFile TARGET ${_target} PROPERTY COTIRE_${_language}_PRECOMPILED_HEADER)
+ set (_flags "")
+ cotire_determine_compiler_version("${_language}" COTIRE_${_language}_COMPILER)
+ cotire_add_prefix_pch_inclusion_flags(
+ "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${COTIRE_${_language}_COMPILER_VERSION}"
+ "${_prefixFile}" "${_pchFile}" _flags)
+ set_property (TARGET ${_target} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ")
+ endif()
+ endif()
+ endif()
+endfunction()
+
+function (cotire_setup_unity_generation_commands _language _targetSourceDir _target _targetScript _unityFiles _cmdsVar)
+ set (_dependencySources "")
+ cotire_get_unity_source_dependencies(${_language} ${_target} _dependencySources ${ARGN})
+ foreach (_unityFile ${_unityFiles})
+ file (RELATIVE_PATH _unityFileRelPath "${CMAKE_BINARY_DIR}" "${_unityFile}")
+ set_property (SOURCE "${_unityFile}" PROPERTY GENERATED TRUE)
+ # set up compiled unity source dependencies
+ # this ensures that missing source files are generated before the unity file is compiled
+ if (COTIRE_DEBUG AND _dependencySources)
+ message (STATUS "${_unityFile} OBJECT_DEPENDS ${_dependencySources}")
+ endif()
+ if (_dependencySources)
+ set_property (SOURCE "${_unityFile}" PROPERTY OBJECT_DEPENDS ${_dependencySources})
+ endif()
+ if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel")
+ # unity file compilation results in potentially huge object file, thus use /bigobj by default unter MSVC and Windows Intel
+ set_property (SOURCE "${_unityFile}" APPEND_STRING PROPERTY COMPILE_FLAGS "/bigobj")
+ endif()
+ cotire_set_cmd_to_prologue(_unityCmd)
+ list (APPEND _unityCmd -P "${COTIRE_CMAKE_MODULE_FILE}" "unity" "${_targetScript}" "${_unityFile}")
+ if (COTIRE_DEBUG)
+ message (STATUS "add_custom_command: OUTPUT ${_unityFile} COMMAND ${_unityCmd} DEPENDS ${_targetScript}")
+ endif()
+ add_custom_command(
+ OUTPUT "${_unityFile}"
+ COMMAND ${_unityCmd}
+ DEPENDS "${_targetScript}"
+ COMMENT "Generating ${_language} unity source ${_unityFileRelPath}"
+ WORKING_DIRECTORY "${_targetSourceDir}" VERBATIM)
+ list (APPEND ${_cmdsVar} COMMAND ${_unityCmd})
+ endforeach()
+ list (LENGTH _unityFiles _numberOfUnityFiles)
+ if (_numberOfUnityFiles GREATER 1)
+ # create a joint unity file from all unity file segments
+ cotire_make_single_unity_source_file_path(${_language} ${_target} _unityFile)
+ cotire_setup_combine_command(${_language} "${_targetSourceDir}" "${_targetScript}" "${_unityFile}" ${_cmdsVar} ${_unityFiles})
+ endif()
+ set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE)
+endfunction()
+
+function (cotire_setup_single_prefix_generation_command _language _target _targetSourceDir _targetScript _prefixFile _unityFile _cmdsVar)
+ set (_sourceFiles ${ARGN})
+ set (_dependencySources "")
+ cotire_get_prefix_header_dependencies(${_language} ${_target} _dependencySources ${_sourceFiles})
+ cotire_set_cmd_to_prologue(_prefixCmd)
+ list (APPEND _prefixCmd -P "${COTIRE_CMAKE_MODULE_FILE}" "prefix" "${_targetScript}" "${_prefixFile}" "${_unityFile}")
+ set_property (SOURCE "${_prefixFile}" PROPERTY GENERATED TRUE)
+ if (COTIRE_DEBUG)
+ message (STATUS "add_custom_command: OUTPUT ${_prefixFile} COMMAND ${_prefixCmd} DEPENDS ${_targetScript} ${_unityFile} ${_dependencySources}")
+ endif()
+ file (RELATIVE_PATH _prefixFileRelPath "${CMAKE_BINARY_DIR}" "${_prefixFile}")
+ add_custom_command(
+ OUTPUT "${_prefixFile}" "${_prefixFile}.log"
+ COMMAND ${_prefixCmd}
+ DEPENDS "${_targetScript}" "${_unityFile}" ${_dependencySources}
+ COMMENT "Generating ${_language} prefix header ${_prefixFileRelPath}"
+ WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" VERBATIM)
+ list (APPEND ${_cmdsVar} COMMAND ${_prefixCmd})
+ set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE)
+endfunction()
+
+function (cotire_setup_multi_prefix_generation_command _language _target _targetSourceDir _targetScript _prefixFile _unityFiles _cmdsVar)
+ set (_sourceFiles ${ARGN})
+ list (LENGTH _unityFiles _numberOfUnityFiles)
+ if (_numberOfUnityFiles GREATER 1)
+ cotire_make_single_unity_source_file_path(${_language} ${_target} _unityFile)
+ cotire_setup_single_prefix_generation_command(
+ ${_language} ${_target} "${_targetSourceDir}" "${_targetScript}"
+ "${_prefixFile}" "${_unityFile}" ${_cmdsVar} ${_sourceFiles})
+ else()
+ cotire_setup_single_prefix_generation_command(
+ ${_language} ${_target} "${_targetSourceDir}" "${_targetScript}"
+ "${_prefixFile}" "${_unityFiles}" ${_cmdsVar} ${_sourceFiles})
+ endif()
+ set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE)
+endfunction()
+
+function (cotire_init_cotire_target_properties _target)
+ get_property(_isSet TARGET ${_target} PROPERTY COTIRE_ENABLE_PRECOMPILED_HEADER SET)
+ if (NOT _isSet)
+ set_property(TARGET ${_target} PROPERTY COTIRE_ENABLE_PRECOMPILED_HEADER TRUE)
+ endif()
+ get_property(_isSet TARGET ${_target} PROPERTY COTIRE_ADD_UNITY_BUILD SET)
+ if (NOT _isSet)
+ set_property(TARGET ${_target} PROPERTY COTIRE_ADD_UNITY_BUILD TRUE)
+ endif()
+ get_property(_isSet TARGET ${_target} PROPERTY COTIRE_ADD_CLEAN SET)
+ if (NOT _isSet)
+ set_property(TARGET ${_target} PROPERTY COTIRE_ADD_CLEAN FALSE)
+ endif()
+ get_property(_isSet TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_IGNORE_PATH SET)
+ if (NOT _isSet)
+ set_property(TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_IGNORE_PATH "${CMAKE_SOURCE_DIR}")
+ cotire_check_is_path_relative_to("${CMAKE_BINARY_DIR}" _isRelative "${CMAKE_SOURCE_DIR}")
+ if (NOT _isRelative)
+ set_property(TARGET ${_target} APPEND PROPERTY COTIRE_PREFIX_HEADER_IGNORE_PATH "${CMAKE_BINARY_DIR}")
+ endif()
+ endif()
+ get_property(_isSet TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PATH SET)
+ if (NOT _isSet)
+ set_property(TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PATH "")
+ endif()
+ get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_PRE_UNDEFS SET)
+ if (NOT _isSet)
+ set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_PRE_UNDEFS "")
+ endif()
+ get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_POST_UNDEFS SET)
+ if (NOT _isSet)
+ set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_POST_UNDEFS "")
+ endif()
+ get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES SET)
+ if (NOT _isSet)
+ if (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES)
+ set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "${COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES}")
+ else()
+ set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "")
+ endif()
+ endif()
+endfunction()
+
+function (cotire_make_target_message _target _languages _disableMsg _targetMsgVar)
+ get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER)
+ get_target_property(_targetAddSCU ${_target} COTIRE_ADD_UNITY_BUILD)
+ string (REPLACE ";" " " _languagesStr "${_languages}")
+ string (REPLACE ";" ", " _excludedStr "${ARGN}")
+ set (_targetMsg "")
+ if (NOT _languages)
+ set (_targetMsg "Target ${_target} cannot be cotired.")
+ if (_disableMsg)
+ set (_targetMsg "${_targetMsg} ${_disableMsg}")
+ endif()
+ elseif (NOT _targetUsePCH AND NOT _targetAddSCU)
+ set (_targetMsg "${_languagesStr} target ${_target} cotired without unity build and precompiled header.")
+ if (_disableMsg)
+ set (_targetMsg "${_targetMsg} ${_disableMsg}")
+ endif()
+ elseif (NOT _targetUsePCH)
+ if (_allExcludedSourceFiles)
+ set (_targetMsg "${_languagesStr} target ${_target} cotired excluding files ${_excludedStr} without precompiled header.")
+ else()
+ set (_targetMsg "${_languagesStr} target ${_target} cotired without precompiled header.")
+ endif()
+ if (_disableMsg)
+ set (_targetMsg "${_targetMsg} ${_disableMsg}")
+ endif()
+ elseif (NOT _targetAddSCU)
+ if (_allExcludedSourceFiles)
+ set (_targetMsg "${_languagesStr} target ${_target} cotired excluding files ${_excludedStr} without unity build.")
+ else()
+ set (_targetMsg "${_languagesStr} target ${_target} cotired without unity build.")
+ endif()
+ else()
+ if (_allExcludedSourceFiles)
+ set (_targetMsg "${_languagesStr} target ${_target} cotired excluding files ${_excludedStr}.")
+ else()
+ set (_targetMsg "${_languagesStr} target ${_target} cotired.")
+ endif()
+ endif()
+ set (${_targetMsgVar} "${_targetMsg}" PARENT_SCOPE)
+endfunction()
+
+function (cotire_choose_target_languages _targetSourceDir _target _targetLanguagesVar)
+ set (_languages ${ARGN})
+ set (_allSourceFiles "")
+ set (_allExcludedSourceFiles "")
+ set (_allCotiredSourceFiles "")
+ set (_targetLanguages "")
+ get_target_property(_targetType ${_target} TYPE)
+ get_target_property(_targetSourceFiles ${_target} SOURCES)
+ get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER)
+ get_target_property(_targetAddSCU ${_target} COTIRE_ADD_UNITY_BUILD)
+ set (_disableMsg "")
+ foreach (_language ${_languages})
+ get_target_property(_prefixHeader ${_target} COTIRE_${_language}_PREFIX_HEADER)
+ get_target_property(_unityBuildFile ${_target} COTIRE_${_language}_UNITY_SOURCE)
+ if (_prefixHeader OR _unityBuildFile)
+ message (WARNING "Target ${_target} has already been cotired.")
+ set (${_targetLanguagesVar} "" PARENT_SCOPE)
+ return()
+ endif()
+ if (_targetUsePCH AND "${_language}" STREQUAL "C" OR "${_language}" STREQUAL "CXX")
+ cotire_check_precompiled_header_support("${_language}" "${_targetSourceDir}" "${_target}" _disableMsg)
+ if (_disableMsg)
+ set (_targetUsePCH FALSE)
+ endif()
+ endif()
+ set (_sourceFiles "")
+ set (_excludedSources "")
+ set (_cotiredSources "")
+ cotire_filter_language_source_files(${_language} _sourceFiles _excludedSources _cotiredSources ${_targetSourceFiles})
+ if (_sourceFiles OR _excludedSources OR _cotiredSources)
+ list (APPEND _targetLanguages ${_language})
+ endif()
+ if (_sourceFiles)
+ list (APPEND _allSourceFiles ${_sourceFiles})
+ endif()
+ if (_excludedSources)
+ list (APPEND _allExcludedSourceFiles ${_excludedSources})
+ endif()
+ if (_cotiredSources)
+ list (APPEND _allCotiredSourceFiles ${_cotiredSources})
+ endif()
+ endforeach()
+ set (_targetMsgLevel STATUS)
+ if (NOT _targetLanguages)
+ string (REPLACE ";" " or " _languagesStr "${_languages}")
+ set (_disableMsg "No ${_languagesStr} source files.")
+ set (_targetUsePCH FALSE)
+ set (_targetAddSCU FALSE)
+ endif()
+ if (_targetUsePCH)
+ list (LENGTH _allSourceFiles _numberOfSources)
+ if (_numberOfSources LESS ${COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES})
+ set (_disableMsg "Too few applicable sources.")
+ set (_targetUsePCH FALSE)
+ elseif (_allCotiredSourceFiles)
+ cotire_get_source_file_property_values(_cotireTargets COTIRE_TARGET ${_allCotiredSourceFiles})
+ list (REMOVE_DUPLICATES _cotireTargets)
+ string (REPLACE ";" ", " _cotireTargetsStr "${_cotireTargets}")
+ set (_disableMsg "Target sources already include a precompiled header for target(s) ${_cotireTargets}.")
+ set (_disableMsg "${_disableMsg} Set target property COTIRE_ENABLE_PRECOMPILED_HEADER to FALSE for targets ${_target},")
+ set (_disableMsg "${_disableMsg} ${_cotireTargetsStr} to get a workable build system.")
+ set (_targetMsgLevel SEND_ERROR)
+ set (_targetUsePCH FALSE)
+ elseif (XCODE AND _allExcludedSourceFiles)
+ # for Xcode, we cannot apply the precompiled header to individual sources, only to the whole target
+ set (_disableMsg "Exclusion of source files not supported for generator Xcode.")
+ set (_targetUsePCH FALSE)
+ elseif (XCODE AND "${_targetType}" STREQUAL "OBJECT_LIBRARY")
+ # for Xcode, we cannot apply the required PRE_BUILD action to generate the prefix header to an OBJECT_LIBRARY target
+ set (_disableMsg "Required PRE_BUILD action not supported for OBJECT_LIBRARY targets for generator Xcode.")
+ set (_targetUsePCH FALSE)
+ endif()
+ endif()
+ set_property(TARGET ${_target} PROPERTY COTIRE_ENABLE_PRECOMPILED_HEADER ${_targetUsePCH})
+ set_property(TARGET ${_target} PROPERTY COTIRE_ADD_UNITY_BUILD ${_targetAddSCU})
+ cotire_make_target_message(${_target} "${_targetLanguages}" "${_disableMsg}" _targetMsg ${_allExcludedSourceFiles})
+ if (_targetMsg)
+ if (NOT DEFINED COTIREMSG_${_target})
+ set (COTIREMSG_${_target} "")
+ endif()
+ if (COTIRE_VERBOSE OR NOT "${_targetMsgLevel}" STREQUAL "STATUS" OR
+ NOT "${COTIREMSG_${_target}}" STREQUAL "${_targetMsg}")
+ # cache message to avoid redundant messages on re-configure
+ set (COTIREMSG_${_target} "${_targetMsg}" CACHE INTERNAL "${_target} cotire message.")
+ message (${_targetMsgLevel} "${_targetMsg}")
+ endif()
+ endif()
+ set (${_targetLanguagesVar} ${_targetLanguages} PARENT_SCOPE)
+endfunction()
+
+function (cotire_compute_unity_max_number_of_includes _target _maxIncludesVar)
+ set (_sourceFiles ${ARGN})
+ get_target_property(_maxIncludes ${_target} COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES)
+ if (_maxIncludes MATCHES "(-j|--parallel|--jobs) ?([0-9]*)")
+ set (_numberOfThreads "${CMAKE_MATCH_2}")
+ if (NOT _numberOfThreads)
+ # use all available cores
+ ProcessorCount(_numberOfThreads)
+ endif()
+ list (LENGTH _sourceFiles _numberOfSources)
+ math (EXPR _maxIncludes "(${_numberOfSources} + ${_numberOfThreads} - 1) / ${_numberOfThreads}")
+ # a unity source segment must not contain less than COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES files
+ if (_maxIncludes LESS ${COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES})
+ set (_maxIncludes ${COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES})
+ endif()
+ elseif (NOT _maxIncludes MATCHES "[0-9]+")
+ set (_maxIncludes 0)
+ endif()
+ if (COTIRE_DEBUG)
+ message (STATUS "${_target} unity source max includes = ${_maxIncludes}")
+ endif()
+ set (${_maxIncludesVar} ${_maxIncludes} PARENT_SCOPE)
+endfunction()
+
+function (cotire_process_target_language _language _configurations _targetSourceDir _targetBinaryDir _target _wholeTargetVar _cmdsVar)
+ set (${_cmdsVar} "" PARENT_SCOPE)
+ get_target_property(_targetSourceFiles ${_target} SOURCES)
+ set (_sourceFiles "")
+ set (_excludedSources "")
+ set (_cotiredSources "")
+ cotire_filter_language_source_files(${_language} _sourceFiles _excludedSources _cotiredSources ${_targetSourceFiles})
+ if (NOT _sourceFiles AND NOT _cotiredSources)
+ return()
+ endif()
+ set (_wholeTarget ${${_wholeTargetVar}})
+ set (_cmds "")
+ # check for user provided unity source file list
+ get_property(_unitySourceFiles TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE_INIT)
+ if (NOT _unitySourceFiles)
+ set (_unitySourceFiles ${_sourceFiles} ${_cotiredSources})
+ endif()
+ cotire_generate_target_script(
+ ${_language} "${_configurations}" "${_targetSourceDir}" "${_targetBinaryDir}" ${_target} _targetScript ${_unitySourceFiles})
+ cotire_compute_unity_max_number_of_includes(${_target} _maxIncludes ${_unitySourceFiles})
+ cotire_make_unity_source_file_paths(${_language} ${_target} ${_maxIncludes} _unityFiles ${_unitySourceFiles})
+ if (NOT _unityFiles)
+ return()
+ endif()
+ cotire_setup_unity_generation_commands(
+ ${_language} "${_targetSourceDir}" ${_target} "${_targetScript}" "${_unityFiles}" _cmds ${_unitySourceFiles})
+ cotire_make_prefix_file_path(${_language} ${_target} _prefixFile)
+ if (_prefixFile)
+ # check for user provided prefix header files
+ get_property(_prefixHeaderFiles TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER_INIT)
+ if (_prefixHeaderFiles)
+ cotire_setup_combine_command(${_language} "${_targetSourceDir}" "${_targetScript}" "${_prefixFile}" _cmds ${_prefixHeaderFiles})
+ else()
+ cotire_setup_multi_prefix_generation_command(
+ ${_language} ${_target} "${_targetSourceDir}" "${_targetScript}" "${_prefixFile}" "${_unityFiles}" _cmds ${_unitySourceFiles})
+ endif()
+ get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER)
+ if (_targetUsePCH)
+ cotire_make_pch_file_path(${_language} "${_targetSourceDir}" ${_target} _pchFile)
+ if (_pchFile)
+ cotire_setup_pch_file_compilation(
+ ${_language} ${_target} "${_targetSourceDir}" "${_targetScript}" "${_prefixFile}" "${_pchFile}" ${_sourceFiles})
+ if (_excludedSources)
+ set (_wholeTarget FALSE)
+ endif()
+ cotire_setup_pch_file_inclusion(
+ ${_language} ${_target} ${_wholeTarget} "${_prefixFile}" "${_pchFile}" ${_sourceFiles})
+ endif()
+ elseif (_prefixHeaderFiles)
+ # user provided prefix header must be included
+ cotire_setup_prefix_file_inclusion(
+ ${_language} ${_target} "${_prefixFile}" ${_sourceFiles})
+ endif()
+ endif()
+ # mark target as cotired for language
+ set_property(TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE "${_unityFiles}")
+ if (_prefixFile)
+ set_property(TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER "${_prefixFile}")
+ if (_targetUsePCH AND _pchFile)
+ set_property(TARGET ${_target} PROPERTY COTIRE_${_language}_PRECOMPILED_HEADER "${_pchFile}")
+ endif()
+ endif()
+ set (${_wholeTargetVar} ${_wholeTarget} PARENT_SCOPE)
+ set (${_cmdsVar} ${_cmds} PARENT_SCOPE)
+endfunction()
+
+function (cotire_setup_clean_target _target)
+ set (_cleanTargetName "${_target}${COTIRE_CLEAN_TARGET_SUFFIX}")
+ if (NOT TARGET "${_cleanTargetName}")
+ cotire_set_cmd_to_prologue(_cmds)
+ get_filename_component(_outputDir "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}" ABSOLUTE)
+ list (APPEND _cmds -P "${COTIRE_CMAKE_MODULE_FILE}" "cleanup" "${_outputDir}" "${COTIRE_INTDIR}" "${_target}")
+ add_custom_target(${_cleanTargetName} COMMAND ${_cmds} WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+ COMMENT "Cleaning up target ${_target} cotire generated files" VERBATIM)
+ cotire_init_target("${_cleanTargetName}")
+ endif()
+endfunction()
+
+function (cotire_setup_pch_target _languages _configurations _target)
+ if ("${CMAKE_GENERATOR}" MATCHES "Makefiles|Ninja")
+ # for makefile based generators, we add a custom target to trigger the generation of the cotire related files
+ set (_dependsFiles "")
+ foreach (_language ${_languages})
+ set (_props COTIRE_${_language}_PREFIX_HEADER COTIRE_${_language}_UNITY_SOURCE)
+ if (NOT CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel")
+ # Visual Studio and Intel only create precompiled header as a side effect
+ list (INSERT _props 0 COTIRE_${_language}_PRECOMPILED_HEADER)
+ endif()
+ cotire_get_first_set_property_value(_dependsFile TARGET ${_target} ${_props})
+ if (_dependsFile)
+ list (APPEND _dependsFiles "${_dependsFile}")
+ endif()
+ endforeach()
+ if (_dependsFiles)
+ set (_pchTargetName "${_target}${COTIRE_PCH_TARGET_SUFFIX}")
+ add_custom_target("${_pchTargetName}" DEPENDS ${_dependsFiles})
+ cotire_init_target("${_pchTargetName}")
+ cotire_add_to_pch_all_target(${_pchTargetName})
+ endif()
+ else()
+ # for other generators, we add the "clean all" target to clean up the precompiled header
+ cotire_setup_clean_all_target()
+ endif()
+endfunction()
+
+function (cotire_setup_unity_build_target _languages _configurations _targetSourceDir _target)
+ get_target_property(_unityTargetName ${_target} COTIRE_UNITY_TARGET_NAME)
+ if (NOT _unityTargetName)
+ set (_unityTargetName "${_target}${COTIRE_UNITY_BUILD_TARGET_SUFFIX}")
+ endif()
+ # determine unity target sub type
+ get_target_property(_targetType ${_target} TYPE)
+ if ("${_targetType}" STREQUAL "EXECUTABLE")
+ get_target_property(_isWin32 ${_target} WIN32_EXECUTABLE)
+ get_target_property(_isMacOSX_Bundle ${_target} MACOSX_BUNDLE)
+ if (_isWin32)
+ set (_unityTargetSubType WIN32)
+ elseif (_isMacOSX_Bundle)
+ set (_unityTargetSubType MACOSX_BUNDLE)
+ else()
+ set (_unityTargetSubType "")
+ endif()
+ elseif (_targetType MATCHES "(STATIC|SHARED|MODULE|OBJECT)_LIBRARY")
+ set (_unityTargetSubType "${CMAKE_MATCH_1}")
+ else()
+ message (WARNING "Unknown target type ${_targetType}.")
+ return()
+ endif()
+ # determine unity target sources
+ get_target_property(_targetSourceFiles ${_target} SOURCES)
+ set (_unityTargetSources ${_targetSourceFiles})
+ foreach (_language ${_languages})
+ get_property(_unityFiles TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE)
+ if (_unityFiles)
+ # remove source files that are included in the unity source
+ set (_sourceFiles "")
+ set (_excludedSources "")
+ set (_cotiredSources "")
+ cotire_filter_language_source_files(${_language} _sourceFiles _excludedSources _cotiredSources ${_targetSourceFiles})
+ if (_sourceFiles OR _cotiredSources)
+ list (REMOVE_ITEM _unityTargetSources ${_sourceFiles} ${_cotiredSources})
+ endif()
+ # if cotire is applied to a target which has not been added in the current source dir,
+ # non-existing files cannot be referenced from the unity build target (this is a CMake restriction)
+ if (NOT "${_targetSourceDir}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
+ set (_nonExistingFiles "")
+ foreach (_file ${_unityTargetSources})
+ if (NOT EXISTS "${_file}")
+ list (APPEND _nonExistingFiles "${_file}")
+ endif()
+ endforeach()
+ if (_nonExistingFiles)
+ if (COTIRE_VERBOSE)
+ message (STATUS "removing non-existing ${_nonExistingFiles} from ${_unityTargetName}")
+ endif()
+ list (REMOVE_ITEM _unityTargetSources ${_nonExistingFiles})
+ endif()
+ endif()
+ # add unity source files instead
+ list (APPEND _unityTargetSources ${_unityFiles})
+ endif()
+ endforeach()
+ if (COTIRE_DEBUG)
+ message (STATUS "add ${_targetType} ${_unityTargetName} ${_unityTargetSubType} EXCLUDE_FROM_ALL ${_unityTargetSources}")
+ endif()
+ # generate unity target
+ if ("${_targetType}" STREQUAL "EXECUTABLE")
+ add_executable(${_unityTargetName} ${_unityTargetSubType} EXCLUDE_FROM_ALL ${_unityTargetSources})
+ else()
+ add_library(${_unityTargetName} ${_unityTargetSubType} EXCLUDE_FROM_ALL ${_unityTargetSources})
+ endif()
+ set (_outputDirProperties
+ ARCHIVE_OUTPUT_DIRECTORY ARCHIVE_OUTPUT_DIRECTORY_<CONFIG>
+ LIBRARY_OUTPUT_DIRECTORY LIBRARY_OUTPUT_DIRECTORY_<CONFIG>
+ RUNTIME_OUTPUT_DIRECTORY RUNTIME_OUTPUT_DIRECTORY_<CONFIG>)
+ # copy output location properties
+ if (COTIRE_UNITY_OUTPUT_DIRECTORY)
+ set (_setDefaultOutputDir TRUE)
+ if (IS_ABSOLUTE "${COTIRE_UNITY_OUTPUT_DIRECTORY}")
+ set (_outputDir "${COTIRE_UNITY_OUTPUT_DIRECTORY}")
+ else()
+ cotrie_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} ${_outputDirProperties})
+ cotrie_resolve_config_properites("${_configurations}" _properties ${_outputDirProperties})
+ foreach (_property ${_properties})
+ get_property(_outputDir TARGET ${_target} PROPERTY ${_property})
+ if (_outputDir)
+ get_filename_component(_outputDir "${_outputDir}/${COTIRE_UNITY_OUTPUT_DIRECTORY}" ABSOLUTE)
+ set_property(TARGET ${_unityTargetName} PROPERTY ${_property} "${_outputDir}")
+ set (_setDefaultOutputDir FALSE)
+ endif()
+ endforeach()
+ if (_setDefaultOutputDir)
+ get_filename_component(_outputDir "${CMAKE_CURRENT_BINARY_DIR}/${COTIRE_UNITY_OUTPUT_DIRECTORY}" ABSOLUTE)
+ endif()
+ endif()
+ if (_setDefaultOutputDir)
+ set_target_properties(${_unityTargetName} PROPERTIES
+ ARCHIVE_OUTPUT_DIRECTORY "${_outputDir}"
+ LIBRARY_OUTPUT_DIRECTORY "${_outputDir}"
+ RUNTIME_OUTPUT_DIRECTORY "${_outputDir}")
+ endif()
+ else()
+ cotrie_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} ${_outputDirProperties})
+ endif()
+ # copy output name
+ cotrie_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName}
+ ARCHIVE_OUTPUT_NAME ARCHIVE_OUTPUT_NAME_<CONFIG>
+ LIBRARY_OUTPUT_NAME LIBRARY_OUTPUT_NAME_<CONFIG>
+ OUTPUT_NAME OUTPUT_NAME_<CONFIG>
+ RUNTIME_OUTPUT_NAME RUNTIME_OUTPUT_NAME_<CONFIG>
+ PREFIX <CONFIG>_POSTFIX SUFFIX)
+ # copy compile stuff
+ cotrie_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName}
+ COMPILE_DEFINITIONS COMPILE_DEFINITIONS_<CONFIG>
+ COMPILE_FLAGS Fortran_FORMAT
+ INCLUDE_DIRECTORIES
+ INTERPROCEDURAL_OPTIMIZATION INTERPROCEDURAL_OPTIMIZATION_<CONFIG>
+ POSITION_INDEPENDENT_CODE)
+ # copy link stuff
+ cotrie_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName}
+ BUILD_WITH_INSTALL_RPATH INSTALL_RPATH INSTALL_RPATH_USE_LINK_PATH SKIP_BUILD_RPATH
+ LINKER_LANGUAGE LINK_DEPENDS LINK_DEPENDS_NO_SHARED
+ LINK_FLAGS LINK_FLAGS_<CONFIG>
+ LINK_INTERFACE_LIBRARIES LINK_INTERFACE_LIBRARIES_<CONFIG>
+ LINK_INTERFACE_MULTIPLICITY LINK_INTERFACE_MULTIPLICITY_<CONFIG>
+ LINK_SEARCH_START_STATIC LINK_SEARCH_END_STATIC
+ STATIC_LIBRARY_FLAGS STATIC_LIBRARY_FLAGS_<CONFIG>
+ NO_SONAME SOVERSION VERSION)
+ # copy Qt stuff
+ cotrie_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName}
+ AUTOMOC AUTOMOC_MOC_OPTIONS)
+ # copy cmake stuff
+ cotrie_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName}
+ IMPLICIT_DEPENDS_INCLUDE_TRANSFORM RULE_LAUNCH_COMPILE RULE_LAUNCH_CUSTOM RULE_LAUNCH_LINK)
+ # copy platform stuff
+ if (APPLE)
+ cotrie_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName}
+ BUNDLE BUNDLE_EXTENSION FRAMEWORK INSTALL_NAME_DIR MACOSX_BUNDLE_INFO_PLIST MACOSX_FRAMEWORK_INFO_PLIST
+ OSX_ARCHITECTURES OSX_ARCHITECTURES_<CONFIG> PRIVATE_HEADER PUBLIC_HEADER RESOURCE)
+ elseif (WIN32)
+ cotrie_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName}
+ GNUtoMS
+ PDB_NAME PDB_NAME_<CONFIG> PDB_OUTPUT_DIRECTORY PDB_OUTPUT_DIRECTORY_<CONFIG>
+ VS_DOTNET_REFERENCES VS_GLOBAL_KEYWORD VS_GLOBAL_PROJECT_TYPES VS_KEYWORD
+ VS_SCC_AUXPATH VS_SCC_LOCALPATH VS_SCC_PROJECTNAME VS_SCC_PROVIDER
+ VS_WINRT_EXTENSIONS VS_WINRT_REFERENCES)
+ endif()
+ # use output name from original target
+ get_target_property(_targetOutputName ${_unityTargetName} OUTPUT_NAME)
+ if (NOT _targetOutputName)
+ set_property(TARGET ${_unityTargetName} PROPERTY OUTPUT_NAME "${_target}")
+ endif()
+ # use export symbol from original target
+ cotire_get_target_export_symbol("${_target}" _defineSymbol)
+ if (_defineSymbol)
+ set_property(TARGET ${_unityTargetName} PROPERTY DEFINE_SYMBOL "${_defineSymbol}")
+ if ("${_targetType}" STREQUAL "EXECUTABLE")
+ set_property(TARGET ${_unityTargetName} PROPERTY ENABLE_EXPORTS TRUE)
+ endif()
+ endif()
+ cotire_init_target(${_unityTargetName})
+ cotire_add_to_unity_all_target(${_unityTargetName})
+ set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_TARGET_NAME "${_unityTargetName}")
+endfunction(cotire_setup_unity_build_target)
+
+function (cotire_target _target)
+ set(_options "")
+ set(_oneValueArgs SOURCE_DIR BINARY_DIR)
+ set(_multiValueArgs LANGUAGES CONFIGURATIONS)
+ cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
+ if (NOT _option_SOURCE_DIR)
+ set (_option_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
+ endif()
+ if (NOT _option_BINARY_DIR)
+ set (_option_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}")
+ endif()
+ if (NOT _option_LANGUAGES)
+ get_property (_option_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
+ endif()
+ if (NOT _option_CONFIGURATIONS)
+ if (CMAKE_CONFIGURATION_TYPES)
+ set (_option_CONFIGURATIONS ${CMAKE_CONFIGURATION_TYPES})
+ elseif (CMAKE_BUILD_TYPE)
+ set (_option_CONFIGURATIONS "${CMAKE_BUILD_TYPE}")
+ else()
+ set (_option_CONFIGURATIONS "None")
+ endif()
+ endif()
+ # trivial checks
+ get_target_property(_imported ${_target} IMPORTED)
+ if (_imported)
+ message (WARNING "Imported target ${_target} cannot be cotired.")
+ return()
+ endif()
+ # check if target needs to be cotired for build type
+ # when using configuration types, the test is performed at build time
+ cotire_init_cotire_target_properties(${_target})
+ if (NOT CMAKE_CONFIGURATION_TYPES)
+ if (CMAKE_BUILD_TYPE)
+ list (FIND _option_CONFIGURATIONS "${CMAKE_BUILD_TYPE}" _index)
+ else()
+ list (FIND _option_CONFIGURATIONS "None" _index)
+ endif()
+ if (_index EQUAL -1)
+ if (COTIRE_DEBUG)
+ message (STATUS "CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} not cotired (${_option_CONFIGURATIONS})")
+ endif()
+ return()
+ endif()
+ endif()
+ # choose languages that apply to the target
+ cotire_choose_target_languages("${_option_SOURCE_DIR}" "${_target}" _targetLanguages ${_option_LANGUAGES})
+ if (NOT _targetLanguages)
+ return()
+ endif()
+ list (LENGTH _targetLanguages _numberOfLanguages)
+ if (_numberOfLanguages GREATER 1)
+ set (_wholeTarget FALSE)
+ else()
+ set (_wholeTarget TRUE)
+ endif()
+ set (_cmds "")
+ foreach (_language ${_targetLanguages})
+ cotire_process_target_language("${_language}" "${_option_CONFIGURATIONS}"
+ "${_option_SOURCE_DIR}" "${_option_BINARY_DIR}" ${_target} _wholeTarget _cmd)
+ if (_cmd)
+ list (APPEND _cmds ${_cmd})
+ endif()
+ endforeach()
+ get_target_property(_targetAddSCU ${_target} COTIRE_ADD_UNITY_BUILD)
+ if (_targetAddSCU)
+ cotire_setup_unity_build_target("${_targetLanguages}" "${_option_CONFIGURATIONS}" "${_option_SOURCE_DIR}" ${_target})
+ endif()
+ get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER)
+ if (_targetUsePCH)
+ cotire_setup_target_pch_usage("${_targetLanguages}" "${_option_SOURCE_DIR}" ${_target} ${_wholeTarget} ${_cmds})
+ cotire_setup_pch_target("${_targetLanguages}" "${_option_CONFIGURATIONS}" ${_target})
+ endif()
+ get_target_property(_targetAddCleanTarget ${_target} COTIRE_ADD_CLEAN)
+ if (_targetAddCleanTarget)
+ cotire_setup_clean_target(${_target})
+ endif()
+endfunction()
+
+function (cotire_cleanup _binaryDir _cotireIntermediateDirName _targetName)
+ if (_targetName)
+ file (GLOB_RECURSE _cotireFiles "${_binaryDir}/${_targetName}*.*")
+ else()
+ file (GLOB_RECURSE _cotireFiles "${_binaryDir}/*.*")
+ endif()
+ # filter files in intermediate directory
+ set (_filesToRemove "")
+ foreach (_file ${_cotireFiles})
+ get_filename_component(_dir "${_file}" PATH)
+ get_filename_component(_dirName "${_dir}" NAME)
+ if ("${_dirName}" STREQUAL "${_cotireIntermediateDirName}")
+ list (APPEND _filesToRemove "${_file}")
+ endif()
+ endforeach()
+ if (_filesToRemove)
+ if (COTIRE_VERBOSE)
+ message (STATUS "removing ${_filesToRemove}")
+ endif()
+ file (REMOVE ${_filesToRemove})
+ endif()
+endfunction()
+
+function (cotire_init_target _targetName)
+ if (COTIRE_TARGETS_FOLDER)
+ set_target_properties(${_targetName} PROPERTIES FOLDER "${COTIRE_TARGETS_FOLDER}")
+ endif()
+ if (MSVC_IDE)
+ set_target_properties(${_targetName} PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD TRUE)
+ endif()
+endfunction()
+
+function (cotire_add_to_pch_all_target _pchTargetName)
+ set (_targetName "${COTIRE_PCH_ALL_TARGET_NAME}")
+ if (NOT TARGET "${_targetName}")
+ add_custom_target("${_targetName}" WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" VERBATIM)
+ cotire_init_target("${_targetName}")
+ endif()
+ cotire_setup_clean_all_target()
+ add_dependencies(${_targetName} ${_pchTargetName})
+endfunction()
+
+function (cotire_add_to_unity_all_target _unityTargetName)
+ set (_targetName "${COTIRE_UNITY_BUILD_ALL_TARGET_NAME}")
+ if (NOT TARGET "${_targetName}")
+ add_custom_target("${_targetName}" WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" VERBATIM)
+ cotire_init_target("${_targetName}")
+ endif()
+ cotire_setup_clean_all_target()
+ add_dependencies(${_targetName} ${_unityTargetName})
+endfunction()
+
+function (cotire_setup_clean_all_target)
+ set (_targetName "${COTIRE_CLEAN_ALL_TARGET_NAME}")
+ if (NOT TARGET "${_targetName}")
+ cotire_set_cmd_to_prologue(_cmds)
+ list (APPEND _cmds -P "${COTIRE_CMAKE_MODULE_FILE}" "cleanup" "${CMAKE_BINARY_DIR}" "${COTIRE_INTDIR}")
+ add_custom_target(${_targetName} COMMAND ${_cmds}
+ WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" COMMENT "Cleaning up all cotire generated files" VERBATIM)
+ cotire_init_target("${_targetName}")
+ endif()
+endfunction()
+
+function (cotire)
+ set(_options "")
+ set(_oneValueArgs SOURCE_DIR BINARY_DIR)
+ set(_multiValueArgs LANGUAGES CONFIGURATIONS)
+ cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
+ set (_targets ${_option_UNPARSED_ARGUMENTS})
+ if (NOT _option_SOURCE_DIR)
+ set (_option_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
+ endif()
+ if (NOT _option_BINARY_DIR)
+ set (_option_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}")
+ endif()
+ foreach (_target ${_targets})
+ if (TARGET ${_target})
+ cotire_target(${_target} LANGUAGES ${_option_LANGUAGES} CONFIGURATIONS ${_option_CONFIGURATIONS}
+ SOURCE_DIR "${_option_SOURCE_DIR}" BINARY_DIR "${_option_BINARY_DIR}")
+ else()
+ message (WARNING "${_target} is not a target")
+ endif()
+ endforeach()
+endfunction()
+
+if (CMAKE_SCRIPT_MODE_FILE)
+
+ # cotire is being run in script mode
+ # locate -P on command args
+ set (COTIRE_ARGC -1)
+ foreach (_index RANGE ${CMAKE_ARGC})
+ if (COTIRE_ARGC GREATER -1)
+ set (COTIRE_ARGV${COTIRE_ARGC} "${CMAKE_ARGV${_index}}")
+ math (EXPR COTIRE_ARGC "${COTIRE_ARGC} + 1")
+ elseif ("${CMAKE_ARGV${_index}}" STREQUAL "-P")
+ set (COTIRE_ARGC 0)
+ endif()
+ endforeach()
+
+ # include target script if available
+ if ("${COTIRE_ARGV2}" MATCHES "\\.cmake$")
+ # the included target scripts sets up additional variables relating to the target (e.g., COTIRE_TARGET_SOURCES)
+ include("${COTIRE_ARGV2}")
+ endif()
+
+ if (COTIRE_DEBUG)
+ message (STATUS "${COTIRE_ARGV0} ${COTIRE_ARGV1} ${COTIRE_ARGV2} ${COTIRE_ARGV3} ${COTIRE_ARGV4} ${COTIRE_ARGV5}")
+ endif()
+
+ if (WIN32)
+ # for MSVC, compiler IDs may not always be set correctly
+ if (MSVC)
+ set (CMAKE_C_COMPILER_ID "MSVC")
+ set (CMAKE_CXX_COMPILER_ID "MSVC")
+ endif()
+ endif()
+
+ if (NOT COTIRE_BUILD_TYPE)
+ set (COTIRE_BUILD_TYPE "None")
+ endif()
+ string (TOUPPER "${COTIRE_BUILD_TYPE}" _upperConfig)
+ set (_includeDirs ${COTIRE_TARGET_INCLUDE_DIRECTORIES_${_upperConfig}})
+ set (_compileDefinitions ${COTIRE_TARGET_COMPILE_DEFINITIONS_${_upperConfig}})
+ set (_compileFlags ${COTIRE_TARGET_COMPILE_FLAGS_${_upperConfig}})
+ # check if target has been cotired for actual build type COTIRE_BUILD_TYPE
+ list (FIND COTIRE_TARGET_CONFIGURATION_TYPES "${COTIRE_BUILD_TYPE}" _index)
+ if (_index GREATER -1)
+ set (_sources ${COTIRE_TARGET_SOURCES})
+ set (_sourcesDefinitions ${COTIRE_TARGET_SOURCES_COMPILE_DEFINITIONS_${_upperConfig}})
+ else()
+ if (COTIRE_DEBUG)
+ message (STATUS "COTIRE_BUILD_TYPE=${COTIRE_BUILD_TYPE} not cotired (${COTIRE_TARGET_CONFIGURATION_TYPES})")
+ endif()
+ set (_sources "")
+ set (_sourcesDefinitions "")
+ endif()
+ set (_targetPreUndefs ${COTIRE_TARGET_PRE_UNDEFS})
+ set (_targetPostUndefs ${COTIRE_TARGET_POST_UNDEFS})
+ set (_sourcesPreUndefs ${COTIRE_TARGET_SOURCES_PRE_UNDEFS})
+ set (_sourcesPostUndefs ${COTIRE_TARGET_SOURCES_POST_UNDEFS})
+
+ if ("${COTIRE_ARGV1}" STREQUAL "unity")
+
+ cotire_select_unity_source_files("${COTIRE_ARGV3}" _sources ${_sources})
+ cotire_generate_unity_source(
+ "${COTIRE_ARGV3}" ${_sources}
+ LANGUAGE "${COTIRE_TARGET_LANGUAGE}"
+ DEPENDS "${COTIRE_ARGV0}" "${COTIRE_ARGV2}"
+ SOURCES_COMPILE_DEFINITIONS ${_sourcesDefinitions}
+ PRE_UNDEFS ${_targetPreUndefs}
+ POST_UNDEFS ${_targetPostUndefs}
+ SOURCES_PRE_UNDEFS ${_sourcesPreUndefs}
+ SOURCES_POST_UNDEFS ${_sourcesPostUndefs})
+
+ elseif ("${COTIRE_ARGV1}" STREQUAL "prefix")
+
+ set (_files "")
+ foreach (_index RANGE 4 ${COTIRE_ARGC})
+ if (COTIRE_ARGV${_index})
+ list (APPEND _files "${COTIRE_ARGV${_index}}")
+ endif()
+ endforeach()
+
+ cotire_generate_prefix_header(
+ "${COTIRE_ARGV3}" ${_files}
+ COMPILER_EXECUTABLE "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER}"
+ COMPILER_ARG1 ${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ARG1}
+ COMPILER_ID "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ID}"
+ COMPILER_VERSION "${COTIRE_${COTIRE_TARGET_LANGUAGE}_COMPILER_VERSION}"
+ LANGUAGE "${COTIRE_TARGET_LANGUAGE}"
+ DEPENDS "${COTIRE_ARGV0}" "${COTIRE_ARGV4}" ${COTIRE_TARGET_PREFIX_DEPENDS}
+ IGNORE_PATH "${COTIRE_TARGET_IGNORE_PATH};${COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_PATH}"
+ INCLUDE_PATH ${COTIRE_TARGET_INCLUDE_PATH}
+ IGNORE_EXTENSIONS "${CMAKE_${COTIRE_TARGET_LANGUAGE}_SOURCE_FILE_EXTENSIONS};${COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_EXTENSIONS}"
+ INCLUDE_DIRECTORIES ${_includeDirs}
+ COMPILE_DEFINITIONS ${_compileDefinitions}
+ COMPILE_FLAGS ${_compileFlags})
+
+ elseif ("${COTIRE_ARGV1}" STREQUAL "precompile")
+
+ set (_files "")
+ foreach (_index RANGE 5 ${COTIRE_ARGC})
+ if (COTIRE_ARGV${_index})
+ list (APPEND _files "${COTIRE_ARGV${_index}}")
+ endif()
+ endforeach()
+
+ cotire_precompile_prefix_header(
+ "${COTIRE_ARGV3}" "${COTIRE_ARGV4}" "${COTIRE_ARGV5}"
+ COMPILER_EXECUTABLE "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER}"
+ COMPILER_ARG1 ${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ARG1}
+ COMPILER_ID "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ID}"
+ COMPILER_VERSION "${COTIRE_${COTIRE_TARGET_LANGUAGE}_COMPILER_VERSION}"
+ LANGUAGE "${COTIRE_TARGET_LANGUAGE}"
+ INCLUDE_DIRECTORIES ${_includeDirs}
+ COMPILE_DEFINITIONS ${_compileDefinitions}
+ COMPILE_FLAGS ${_compileFlags})
+
+ elseif ("${COTIRE_ARGV1}" STREQUAL "combine")
+
+ if (COTIRE_TARGET_LANGUAGE)
+ set (_startIndex 3)
+ else()
+ set (_startIndex 2)
+ endif()
+ set (_files "")
+ foreach (_index RANGE ${_startIndex} ${COTIRE_ARGC})
+ if (COTIRE_ARGV${_index})
+ list (APPEND _files "${COTIRE_ARGV${_index}}")
+ endif()
+ endforeach()
+ if (COTIRE_TARGET_LANGUAGE)
+ cotire_generate_unity_source(${_files} LANGUAGE "${COTIRE_TARGET_LANGUAGE}")
+ else()
+ cotire_generate_unity_source(${_files})
+ endif()
+
+ elseif ("${COTIRE_ARGV1}" STREQUAL "cleanup")
+
+ cotire_cleanup("${COTIRE_ARGV2}" "${COTIRE_ARGV3}" "${COTIRE_ARGV4}")
+
+ else()
+ message (FATAL_ERROR "Unknown cotire command \"${COTIRE_ARGV1}\".")
+ endif()
+
+else()
+
+ # cotire is being run in include mode
+ # set up all variable and property definitions
+
+ unset (COTIRE_C_COMPILER_VERSION CACHE)
+ unset (COTIRE_CXX_COMPILER_VERSION CACHE)
+
+ if (NOT DEFINED COTIRE_DEBUG_INIT)
+ if (DEFINED COTIRE_DEBUG)
+ set (COTIRE_DEBUG_INIT ${COTIRE_DEBUG})
+ else()
+ set (COTIRE_DEBUG_INIT FALSE)
+ endif()
+ endif()
+ option (COTIRE_DEBUG "Enable cotire debugging output?" ${COTIRE_DEBUG_INIT})
+
+ if (NOT DEFINED COTIRE_VERBOSE_INIT)
+ if (DEFINED COTIRE_VERBOSE)
+ set (COTIRE_VERBOSE_INIT ${COTIRE_VERBOSE})
+ else()
+ set (COTIRE_VERBOSE_INIT FALSE)
+ endif()
+ endif()
+ option (COTIRE_VERBOSE "Enable cotire verbose output?" ${COTIRE_VERBOSE_INIT})
+
+ set (COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_EXTENSIONS "inc;inl;ipp" CACHE STRING
+ "Ignore headers with the listed file extensions from the generated prefix header.")
+
+ set (COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_PATH "" CACHE STRING
+ "Ignore headers from these directories when generating the prefix header.")
+
+ set (COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS "m;mm" CACHE STRING
+ "Ignore sources with the listed file extensions from the generated unity source.")
+
+ set (COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES "3" CACHE STRING
+ "Minimum number of sources in target required to enable use of precompiled header.")
+
+ if (NOT DEFINED COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT)
+ if (DEFINED COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES)
+ set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT ${COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES})
+ elseif ("${CMAKE_GENERATOR}" MATCHES "JOM|Ninja|Visual Studio")
+ # enable parallelization for generators that run multiple jobs by default
+ set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT "-j")
+ else()
+ set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT "0")
+ endif()
+ endif()
+ set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES "${COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT}" CACHE STRING
+ "Maximum number of source files to include in a single unity source file.")
+
+ if (NOT COTIRE_PREFIX_HEADER_FILENAME_SUFFIX)
+ set (COTIRE_PREFIX_HEADER_FILENAME_SUFFIX "_prefix")
+ endif()
+ if (NOT COTIRE_UNITY_SOURCE_FILENAME_SUFFIX)
+ set (COTIRE_UNITY_SOURCE_FILENAME_SUFFIX "_unity")
+ endif()
+ if (NOT COTIRE_INTDIR)
+ set (COTIRE_INTDIR "cotire")
+ endif()
+ if (NOT COTIRE_PCH_ALL_TARGET_NAME)
+ set (COTIRE_PCH_ALL_TARGET_NAME "all_pch")
+ endif()
+ if (NOT COTIRE_UNITY_BUILD_ALL_TARGET_NAME)
+ set (COTIRE_UNITY_BUILD_ALL_TARGET_NAME "all_unity")
+ endif()
+ if (NOT COTIRE_CLEAN_ALL_TARGET_NAME)
+ set (COTIRE_CLEAN_ALL_TARGET_NAME "clean_cotire")
+ endif()
+ if (NOT COTIRE_CLEAN_TARGET_SUFFIX)
+ set (COTIRE_CLEAN_TARGET_SUFFIX "_clean_cotire")
+ endif()
+ if (NOT COTIRE_PCH_TARGET_SUFFIX)
+ set (COTIRE_PCH_TARGET_SUFFIX "_pch")
+ endif()
+ if (NOT COTIRE_UNITY_BUILD_TARGET_SUFFIX)
+ set (COTIRE_UNITY_BUILD_TARGET_SUFFIX "_unity")
+ endif()
+ if (NOT DEFINED COTIRE_TARGETS_FOLDER)
+ set (COTIRE_TARGETS_FOLDER "cotire")
+ endif()
+ if (NOT DEFINED COTIRE_UNITY_OUTPUT_DIRECTORY)
+ if ("${CMAKE_GENERATOR}" MATCHES "Ninja")
+ # generated Ninja build files do not work if the unity target produces the same output file as the cotired target
+ set (COTIRE_UNITY_OUTPUT_DIRECTORY "unity")
+ else()
+ set (COTIRE_UNITY_OUTPUT_DIRECTORY "")
+ endif()
+ endif()
+
+ # define cotire cache variables
+
+ define_property(
+ CACHED_VARIABLE PROPERTY "COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_PATH"
+ BRIEF_DOCS "Ignore headers from these directories when generating the prefix header."
+ FULL_DOCS
+ "The variable can be set to a semicolon separated list of include directories."
+ "If a header file is found in one of these directories or sub-directories, it will be excluded from the generated prefix header."
+ "If not defined, defaults to empty list."
+ )
+
+ define_property(
+ CACHED_VARIABLE PROPERTY "COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_EXTENSIONS"
+ BRIEF_DOCS "Ignore includes with the listed file extensions from the generated prefix header."
+ FULL_DOCS
+ "The variable can be set to a semicolon separated list of file extensions."
+ "If a header file extension matches one in the list, it will be excluded from the generated prefix header."
+ "Includes with an extension in CMAKE_<LANG>_SOURCE_FILE_EXTENSIONS are always ignored."
+ "If not defined, defaults to inc;inl;ipp."
+ )
+
+ define_property(
+ CACHED_VARIABLE PROPERTY "COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS"
+ BRIEF_DOCS "Exclude sources with the listed file extensions from the generated unity source."
+ FULL_DOCS
+ "The variable can be set to a semicolon separated list of file extensions."
+ "If a source file extension matches one in the list, it will be excluded from the generated unity source file."
+ "Source files with an extension in CMAKE_<LANG>_IGNORE_EXTENSIONS are always excluded."
+ "If not defined, defaults to m;mm."
+ )
+
+ define_property(
+ CACHED_VARIABLE PROPERTY "COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES"
+ BRIEF_DOCS "Minimum number of sources in target required to enable use of precompiled header."
+ FULL_DOCS
+ "The variable can be set to an integer > 0."
+ "If a target contains less than that number of source files, cotire will not enable the use of the precompiled header for the target."
+ "If not defined, defaults to 3."
+ )
+
+ define_property(
+ CACHED_VARIABLE PROPERTY "COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES"
+ BRIEF_DOCS "Maximum number of source files to include in a single unity source file."
+ FULL_DOCS
+ "This may be set to an integer >= 0."
+ "If 0, cotire will only create a single unity source file."
+ "If a target contains more than that number of source files, cotire will create multiple unity source files for it."
+ "Can be set to \"-j\" to optimize the count of unity source files for the number of available processor cores."
+ "Can be set to \"-j jobs\" to optimize the number of unity source files for the given number of simultaneous jobs."
+ "Is used to initialize the target property COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES."
+ "Defaults to \"-j\" for the generators Visual Studio, JOM or Ninja. Defaults to 0 otherwise."
+ )
+
+ # define cotire directory properties
+
+ define_property(
+ DIRECTORY PROPERTY "COTIRE_ENABLE_PRECOMPILED_HEADER"
+ BRIEF_DOCS "Modify build command of cotired targets added in this directory to make use of the generated precompiled header."
+ FULL_DOCS
+ "See target property COTIRE_ENABLE_PRECOMPILED_HEADER."
+ )
+
+ define_property(
+ DIRECTORY PROPERTY "COTIRE_ADD_UNITY_BUILD"
+ BRIEF_DOCS "Add a new target that performs a unity build for cotired targets added in this directory."
+ FULL_DOCS
+ "See target property COTIRE_ADD_UNITY_BUILD."
+ )
+
+ define_property(
+ DIRECTORY PROPERTY "COTIRE_ADD_CLEAN"
+ BRIEF_DOCS "Add a new target that cleans all cotire generated files for cotired targets added in this directory."
+ FULL_DOCS
+ "See target property COTIRE_ADD_CLEAN."
+ )
+
+ define_property(
+ DIRECTORY PROPERTY "COTIRE_PREFIX_HEADER_IGNORE_PATH"
+ BRIEF_DOCS "Ignore headers from these directories when generating the prefix header."
+ FULL_DOCS
+ "See target property COTIRE_PREFIX_HEADER_IGNORE_PATH."
+ )
+
+ define_property(
+ DIRECTORY PROPERTY "COTIRE_PREFIX_HEADER_INCLUDE_PATH"
+ BRIEF_DOCS "Honor headers from these directories when generating the prefix header."
+ FULL_DOCS
+ "See target property COTIRE_PREFIX_HEADER_INCLUDE_PATH."
+ )
+
+ define_property(
+ DIRECTORY PROPERTY "COTIRE_UNITY_SOURCE_PRE_UNDEFS"
+ BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file before the inclusion of each source file."
+ FULL_DOCS
+ "See target property COTIRE_UNITY_SOURCE_PRE_UNDEFS."
+ )
+
+ define_property(
+ DIRECTORY PROPERTY "COTIRE_UNITY_SOURCE_POST_UNDEFS"
+ BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file after the inclusion of each source file."
+ FULL_DOCS
+ "See target property COTIRE_UNITY_SOURCE_POST_UNDEFS."
+ )
+
+ define_property(
+ DIRECTORY PROPERTY "COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES"
+ BRIEF_DOCS "Maximum number of source files to include in a single unity source file."
+ FULL_DOCS
+ "See target property COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES."
+ )
+
+ # define cotire target properties
+
+ define_property(
+ TARGET PROPERTY "COTIRE_ENABLE_PRECOMPILED_HEADER" INHERITED
+ BRIEF_DOCS "Modify this target's build command to make use of the generated precompiled header."
+ FULL_DOCS
+ "If this property is set to TRUE, cotire will modify the build command to make use of the generated precompiled header."
+ "Irrespective of the value of this property, cotire will setup custom commands to generate the unity source and prefix header for the target."
+ "For makefile based generators cotire will also set up a custom target to manually invoke the generation of the precompiled header."
+ "The target name will be set to this target's name with the suffix _pch appended."
+ "Inherited from directory."
+ "Defaults to TRUE."
+ )
+
+ define_property(
+ TARGET PROPERTY "COTIRE_ADD_UNITY_BUILD" INHERITED
+ BRIEF_DOCS "Add a new target that performs a unity build for this target."
+ FULL_DOCS
+ "If this property is set to TRUE, cotire creates a new target of the same type that uses the generated unity source file instead of the target sources."
+ "Most of the relevant target properties will be copied from this target to the new unity build target."
+ "Target dependencies and linked libraries have to be manually set up for the new unity build target."
+ "The unity target name will be set to this target's name with the suffix _unity appended."
+ "Inherited from directory."
+ "Defaults to TRUE."
+ )
+
+ define_property(
+ TARGET PROPERTY "COTIRE_ADD_CLEAN" INHERITED
+ BRIEF_DOCS "Add a new target that cleans all cotire generated files for this target."
+ FULL_DOCS
+ "If this property is set to TRUE, cotire creates a new target that clean all files (unity source, prefix header, precompiled header)."
+ "The clean target name will be set to this target's name with the suffix _clean_cotire appended."
+ "Inherited from directory."
+ "Defaults to FALSE."
+ )
+
+ define_property(
+ TARGET PROPERTY "COTIRE_PREFIX_HEADER_IGNORE_PATH" INHERITED
+ BRIEF_DOCS "Ignore headers from these directories when generating the prefix header."
+ FULL_DOCS
+ "The property can be set to a list of directories."
+ "If a header file is found in one of these directories or sub-directories, it will be excluded from the generated prefix header."
+ "Inherited from directory."
+ "If not set, this property is initialized to \${CMAKE_SOURCE_DIR};\${CMAKE_BINARY_DIR}."
+ )
+
+ define_property(
+ TARGET PROPERTY "COTIRE_PREFIX_HEADER_INCLUDE_PATH" INHERITED
+ BRIEF_DOCS "Honor headers from these directories when generating the prefix header."
+ FULL_DOCS
+ "The property can be set to a list of directories."
+ "If a header file is found in one of these directories or sub-directories, it will be included in the generated prefix header."
+ "If a header file is both selected by COTIRE_PREFIX_HEADER_IGNORE_PATH and COTIRE_PREFIX_HEADER_INCLUDE_PATH,"
+ "the option which yields the closer relative path match wins."
+ "Inherited from directory."
+ "If not set, this property is initialized to the empty list."
+ )
+
+ define_property(
+ TARGET PROPERTY "COTIRE_UNITY_SOURCE_PRE_UNDEFS" INHERITED
+ BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file before the inclusion of each target source file."
+ FULL_DOCS
+ "This may be set to a semicolon-separated list of preprocessor symbols."
+ "cotire will add corresponding #undef directives to the generated unit source file before each target source file."
+ "Inherited from directory."
+ "Defaults to empty string."
+ )
+
+ define_property(
+ TARGET PROPERTY "COTIRE_UNITY_SOURCE_POST_UNDEFS" INHERITED
+ BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file after the inclusion of each target source file."
+ FULL_DOCS
+ "This may be set to a semicolon-separated list of preprocessor symbols."
+ "cotire will add corresponding #undef directives to the generated unit source file after each target source file."
+ "Inherited from directory."
+ "Defaults to empty string."
+ )
+
+ define_property(
+ TARGET PROPERTY "COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES" INHERITED
+ BRIEF_DOCS "Maximum number of source files to include in a single unity source file."
+ FULL_DOCS
+ "This may be set to an integer > 0."
+ "If a target contains more than that number of source files, cotire will create multiple unity build files for it."
+ "If not set, cotire will only create a single unity source file."
+ "Inherited from directory."
+ "Defaults to empty."
+ )
+
+ define_property(
+ TARGET PROPERTY "COTIRE_<LANG>_UNITY_SOURCE_INIT"
+ BRIEF_DOCS "User provided unity source file to be used instead of the automatically generated one."
+ FULL_DOCS
+ "If set, cotire will only add the given file(s) to the generated unity source file."
+ "If not set, cotire will add all the target source files to the generated unity source file."
+ "The property can be set to a user provided unity source file."
+ "Defaults to empty."
+ )
+
+ define_property(
+ TARGET PROPERTY "COTIRE_<LANG>_PREFIX_HEADER_INIT"
+ BRIEF_DOCS "User provided prefix header file to be used instead of the automatically generated one."
+ FULL_DOCS
+ "If set, cotire will add the given header file(s) to the generated prefix header file."
+ "If not set, cotire will generate a prefix header by tracking the header files included by the unity source file."
+ "The property can be set to a user provided prefix header file (e.g., stdafx.h)."
+ "Defaults to empty."
+ )
+
+ define_property(
+ TARGET PROPERTY "COTIRE_<LANG>_UNITY_SOURCE"
+ BRIEF_DOCS "Read-only property. The generated <LANG> unity source file(s)."
+ FULL_DOCS
+ "cotire sets this property to the path of the generated <LANG> single computation unit source file for the target."
+ "Defaults to empty string."
+ )
+
+ define_property(
+ TARGET PROPERTY "COTIRE_<LANG>_PREFIX_HEADER"
+ BRIEF_DOCS "Read-only property. The generated <LANG> prefix header file."
+ FULL_DOCS
+ "cotire sets this property to the full path of the generated <LANG> language prefix header for the target."
+ "Defaults to empty string."
+ )
+
+ define_property(
+ TARGET PROPERTY "COTIRE_<LANG>_PRECOMPILED_HEADER"
+ BRIEF_DOCS "Read-only property. The generated <LANG> precompiled header file."
+ FULL_DOCS
+ "cotire sets this property to the full path of the generated <LANG> language precompiled header binary for the target."
+ "Defaults to empty string."
+ )
+
+ define_property(
+ TARGET PROPERTY "COTIRE_UNITY_TARGET_NAME"
+ BRIEF_DOCS "The name of the generated unity build target corresponding to this target."
+ FULL_DOCS
+ "This property can be set to the desired name of the unity target that will be created by cotire."
+ "If not set, the unity target name will be set to this target's name with the suffix _unity appended."
+ "After this target has been processed by cotire, the property is set to the actual name of the generated unity target."
+ "Defaults to empty string."
+ )
+
+ # define cotire source properties
+
+ define_property(
+ SOURCE PROPERTY "COTIRE_EXCLUDED"
+ BRIEF_DOCS "Do not modify source file's build command."
+ FULL_DOCS
+ "If this property is set to TRUE, the source file's build command will not be modified to make use of the precompiled header."
+ "The source file will also be excluded from the generated unity source file."
+ "Source files that have their COMPILE_FLAGS property set will be excluded by default."
+ "Defaults to FALSE."
+ )
+
+ define_property(
+ SOURCE PROPERTY "COTIRE_DEPENDENCY"
+ BRIEF_DOCS "Add this source file to dependencies of the automatically generated prefix header file."
+ FULL_DOCS
+ "If this property is set to TRUE, the source file is added to dependencies of the generated prefix header file."
+ "If the file is modified, cotire will re-generate the prefix header source upon build."
+ "Defaults to FALSE."
+ )
+
+ define_property(
+ SOURCE PROPERTY "COTIRE_UNITY_SOURCE_PRE_UNDEFS"
+ BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file before the inclusion of this source file."
+ FULL_DOCS
+ "This may be set to a semicolon-separated list of preprocessor symbols."
+ "cotire will add corresponding #undef directives to the generated unit source file before this file is included."
+ "Defaults to empty string."
+ )
+
+ define_property(
+ SOURCE PROPERTY "COTIRE_UNITY_SOURCE_POST_UNDEFS"
+ BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file after the inclusion of this source file."
+ FULL_DOCS
+ "This may be set to a semicolon-separated list of preprocessor symbols."
+ "cotire will add corresponding #undef directives to the generated unit source file after this file is included."
+ "Defaults to empty string."
+ )
+
+ define_property(
+ SOURCE PROPERTY "COTIRE_START_NEW_UNITY_SOURCE"
+ BRIEF_DOCS "Start a new unity source file which includes this source file as the first one."
+ FULL_DOCS
+ "If this property is set to TRUE, cotire will complete the current unity file and start a new one."
+ "The new unity source file will include this source file as the first one."
+ "This property essentially works as a separator for unity source files."
+ "Defaults to FALSE."
+ )
+
+ define_property(
+ SOURCE PROPERTY "COTIRE_TARGET"
+ BRIEF_DOCS "Read-only property. Mark this source file as cotired for the given target."
+ FULL_DOCS
+ "cotire sets this property to the name of target, that the source file's build command has been altered for."
+ "Defaults to empty string."
+ )
+
+ message (STATUS "cotire ${COTIRE_CMAKE_MODULE_VERSION} loaded.")
+
+endif() \ No newline at end of file
diff --git a/contrib/src/getopt/getopt.c b/contrib/src/getopt/getopt.c
new file mode 100644
index 0000000..6fcebc6
--- /dev/null
+++ b/contrib/src/getopt/getopt.c
@@ -0,0 +1,562 @@
+/* $OpenBSD: getopt_long.c,v 1.23 2007/10/31 12:34:57 chl Exp $ */
+/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
+
+/*
+ * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron and Thomas Klausner.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <windows.h>
+
+#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */
+
+#ifdef REPLACE_GETOPT
+int opterr = 1; /* if error message should be printed */
+int optind = 1; /* index into parent argv vector */
+int optopt = '?'; /* character checked for validity */
+#undef optreset /* see getopt.h */
+#define optreset __mingw_optreset
+int optreset; /* reset getopt */
+char *optarg; /* argument associated with option */
+#endif
+
+#define PRINT_ERROR ((opterr) && (*options != ':'))
+
+#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
+#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
+#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
+
+/* return values */
+#define BADCH (int)'?'
+#define BADARG ((*options == ':') ? (int)':' : (int)'?')
+#define INORDER (int)1
+
+#ifndef __CYGWIN__
+#define __progname __argv[0]
+#else
+extern char __declspec(dllimport) *__progname;
+#endif
+
+#ifdef __CYGWIN__
+static char EMSG[] = "";
+#else
+#define EMSG ""
+#endif
+
+static int getopt_internal(int, char * const *, const char *,
+ const struct option *, int *, int);
+static int parse_long_options(char * const *, const char *,
+ const struct option *, int *, int);
+static int gcd(int, int);
+static void permute_args(int, int, int, char * const *);
+
+static char *place = EMSG; /* option letter processing */
+
+/* XXX: set optreset to 1 rather than these two */
+static int nonopt_start = -1; /* first non option argument (for permute) */
+static int nonopt_end = -1; /* first option after non options (for permute) */
+
+/* Error messages */
+static const char recargchar[] = "option requires an argument -- %c";
+static const char recargstring[] = "option requires an argument -- %s";
+static const char ambig[] = "ambiguous option -- %.*s";
+static const char noarg[] = "option doesn't take an argument -- %.*s";
+static const char illoptchar[] = "unknown option -- %c";
+static const char illoptstring[] = "unknown option -- %s";
+
+static void
+_vwarnx(const char *fmt,va_list ap)
+{
+ (void)fprintf(stderr,"%s: ",__progname);
+ if (fmt != NULL)
+ (void)vfprintf(stderr,fmt,ap);
+ (void)fprintf(stderr,"\n");
+}
+
+static void
+warnx(const char *fmt,...)
+{
+ va_list ap;
+ va_start(ap,fmt);
+ _vwarnx(fmt,ap);
+ va_end(ap);
+}
+
+/*
+ * Compute the greatest common divisor of a and b.
+ */
+static int
+gcd(int a, int b)
+{
+ int c;
+
+ c = a % b;
+ while (c != 0) {
+ a = b;
+ b = c;
+ c = a % b;
+ }
+
+ return (b);
+}
+
+/*
+ * Exchange the block from nonopt_start to nonopt_end with the block
+ * from nonopt_end to opt_end (keeping the same order of arguments
+ * in each block).
+ */
+static void
+permute_args(int panonopt_start, int panonopt_end, int opt_end,
+ char * const *nargv)
+{
+ int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
+ char *swap;
+
+ /*
+ * compute lengths of blocks and number and size of cycles
+ */
+ nnonopts = panonopt_end - panonopt_start;
+ nopts = opt_end - panonopt_end;
+ ncycle = gcd(nnonopts, nopts);
+ cyclelen = (opt_end - panonopt_start) / ncycle;
+
+ for (i = 0; i < ncycle; i++) {
+ cstart = panonopt_end+i;
+ pos = cstart;
+ for (j = 0; j < cyclelen; j++) {
+ if (pos >= panonopt_end)
+ pos -= nnonopts;
+ else
+ pos += nopts;
+ swap = nargv[pos];
+ /* LINTED const cast */
+ ((char **) nargv)[pos] = nargv[cstart];
+ /* LINTED const cast */
+ ((char **)nargv)[cstart] = swap;
+ }
+ }
+}
+
+/*
+ * parse_long_options --
+ * Parse long options in argc/argv argument vector.
+ * Returns -1 if short_too is set and the option does not match long_options.
+ */
+static int
+parse_long_options(char * const *nargv, const char *options,
+ const struct option *long_options, int *idx, int short_too)
+{
+ char *current_argv, *has_equal;
+ size_t current_argv_len;
+ int i, ambiguous, match;
+
+#define IDENTICAL_INTERPRETATION(_x, _y) \
+ (long_options[(_x)].has_arg == long_options[(_y)].has_arg && \
+ long_options[(_x)].flag == long_options[(_y)].flag && \
+ long_options[(_x)].val == long_options[(_y)].val)
+
+ current_argv = place;
+ match = -1;
+ ambiguous = 0;
+
+ optind++;
+
+ if ((has_equal = strchr(current_argv, '=')) != NULL) {
+ /* argument found (--option=arg) */
+ current_argv_len = has_equal - current_argv;
+ has_equal++;
+ } else
+ current_argv_len = strlen(current_argv);
+
+ for (i = 0; long_options[i].name; i++) {
+ /* find matching long option */
+ if (strncmp(current_argv, long_options[i].name,
+ current_argv_len))
+ continue;
+
+ if (strlen(long_options[i].name) == current_argv_len) {
+ /* exact match */
+ match = i;
+ ambiguous = 0;
+ break;
+ }
+ /*
+ * If this is a known short option, don't allow
+ * a partial match of a single character.
+ */
+ if (short_too && current_argv_len == 1)
+ continue;
+
+ if (match == -1) /* partial match */
+ match = i;
+ else if (!IDENTICAL_INTERPRETATION(i, match))
+ ambiguous = 1;
+ }
+ if (ambiguous) {
+ /* ambiguous abbreviation */
+ if (PRINT_ERROR)
+ warnx(ambig, (int)current_argv_len,
+ current_argv);
+ optopt = 0;
+ return (BADCH);
+ }
+ if (match != -1) { /* option found */
+ if (long_options[match].has_arg == no_argument
+ && has_equal) {
+ if (PRINT_ERROR)
+ warnx(noarg, (int)current_argv_len,
+ current_argv);
+ /*
+ * XXX: GNU sets optopt to val regardless of flag
+ */
+ if (long_options[match].flag == NULL)
+ optopt = long_options[match].val;
+ else
+ optopt = 0;
+ return (BADARG);
+ }
+ if (long_options[match].has_arg == required_argument ||
+ long_options[match].has_arg == optional_argument) {
+ if (has_equal)
+ optarg = has_equal;
+ else if (long_options[match].has_arg ==
+ required_argument) {
+ /*
+ * optional argument doesn't use next nargv
+ */
+ optarg = nargv[optind++];
+ }
+ }
+ if ((long_options[match].has_arg == required_argument)
+ && (optarg == NULL)) {
+ /*
+ * Missing argument; leading ':' indicates no error
+ * should be generated.
+ */
+ if (PRINT_ERROR)
+ warnx(recargstring,
+ current_argv);
+ /*
+ * XXX: GNU sets optopt to val regardless of flag
+ */
+ if (long_options[match].flag == NULL)
+ optopt = long_options[match].val;
+ else
+ optopt = 0;
+ --optind;
+ return (BADARG);
+ }
+ } else { /* unknown option */
+ if (short_too) {
+ --optind;
+ return (-1);
+ }
+ if (PRINT_ERROR)
+ warnx(illoptstring, current_argv);
+ optopt = 0;
+ return (BADCH);
+ }
+ if (idx)
+ *idx = match;
+ if (long_options[match].flag) {
+ *long_options[match].flag = long_options[match].val;
+ return (0);
+ } else
+ return (long_options[match].val);
+#undef IDENTICAL_INTERPRETATION
+}
+
+/*
+ * getopt_internal --
+ * Parse argc/argv argument vector. Called by user level routines.
+ */
+static int
+getopt_internal(int nargc, char * const *nargv, const char *options,
+ const struct option *long_options, int *idx, int flags)
+{
+ char *oli; /* option letter list index */
+ int optchar, short_too;
+ static int posixly_correct = -1;
+
+ if (options == NULL)
+ return (-1);
+
+ /*
+ * XXX Some GNU programs (like cvs) set optind to 0 instead of
+ * XXX using optreset. Work around this braindamage.
+ */
+ if (optind == 0)
+ optind = optreset = 1;
+
+ /*
+ * Disable GNU extensions if POSIXLY_CORRECT is set or options
+ * string begins with a '+'.
+ *
+ * CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or
+ * optreset != 0 for GNU compatibility.
+ */
+ if (posixly_correct == -1 || optreset != 0)
+ posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
+ if (*options == '-')
+ flags |= FLAG_ALLARGS;
+ else if (posixly_correct || *options == '+')
+ flags &= ~FLAG_PERMUTE;
+ if (*options == '+' || *options == '-')
+ options++;
+
+ optarg = NULL;
+ if (optreset)
+ nonopt_start = nonopt_end = -1;
+start:
+ if (optreset || !*place) { /* update scanning pointer */
+ optreset = 0;
+ if (optind >= nargc) { /* end of argument vector */
+ place = EMSG;
+ if (nonopt_end != -1) {
+ /* do permutation, if we have to */
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ optind -= nonopt_end - nonopt_start;
+ }
+ else if (nonopt_start != -1) {
+ /*
+ * If we skipped non-options, set optind
+ * to the first of them.
+ */
+ optind = nonopt_start;
+ }
+ nonopt_start = nonopt_end = -1;
+ return (-1);
+ }
+ if (*(place = nargv[optind]) != '-' ||
+ (place[1] == '\0' && strchr(options, '-') == NULL)) {
+ place = EMSG; /* found non-option */
+ if (flags & FLAG_ALLARGS) {
+ /*
+ * GNU extension:
+ * return non-option as argument to option 1
+ */
+ optarg = nargv[optind++];
+ return (INORDER);
+ }
+ if (!(flags & FLAG_PERMUTE)) {
+ /*
+ * If no permutation wanted, stop parsing
+ * at first non-option.
+ */
+ return (-1);
+ }
+ /* do permutation */
+ if (nonopt_start == -1)
+ nonopt_start = optind;
+ else if (nonopt_end != -1) {
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ nonopt_start = optind -
+ (nonopt_end - nonopt_start);
+ nonopt_end = -1;
+ }
+ optind++;
+ /* process next argument */
+ goto start;
+ }
+ if (nonopt_start != -1 && nonopt_end == -1)
+ nonopt_end = optind;
+
+ /*
+ * If we have "-" do nothing, if "--" we are done.
+ */
+ if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
+ optind++;
+ place = EMSG;
+ /*
+ * We found an option (--), so if we skipped
+ * non-options, we have to permute.
+ */
+ if (nonopt_end != -1) {
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ optind -= nonopt_end - nonopt_start;
+ }
+ nonopt_start = nonopt_end = -1;
+ return (-1);
+ }
+ }
+
+ /*
+ * Check long options if:
+ * 1) we were passed some
+ * 2) the arg is not just "-"
+ * 3) either the arg starts with -- we are getopt_long_only()
+ */
+ if (long_options != NULL && place != nargv[optind] &&
+ (*place == '-' || (flags & FLAG_LONGONLY))) {
+ short_too = 0;
+ if (*place == '-')
+ place++; /* --foo long option */
+ else if (*place != ':' && strchr(options, *place) != NULL)
+ short_too = 1; /* could be short option too */
+
+ optchar = parse_long_options(nargv, options, long_options,
+ idx, short_too);
+ if (optchar != -1) {
+ place = EMSG;
+ return (optchar);
+ }
+ }
+
+ if ((optchar = (int)*place++) == (int)':' ||
+ (optchar == (int)'-' && *place != '\0') ||
+ (oli = strchr(options, optchar)) == NULL) {
+ /*
+ * If the user specified "-" and '-' isn't listed in
+ * options, return -1 (non-option) as per POSIX.
+ * Otherwise, it is an unknown option character (or ':').
+ */
+ if (optchar == (int)'-' && *place == '\0')
+ return (-1);
+ if (!*place)
+ ++optind;
+ if (PRINT_ERROR)
+ warnx(illoptchar, optchar);
+ optopt = optchar;
+ return (BADCH);
+ }
+ if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
+ /* -W long-option */
+ if (*place) /* no space */
+ /* NOTHING */;
+ else if (++optind >= nargc) { /* no arg */
+ place = EMSG;
+ if (PRINT_ERROR)
+ warnx(recargchar, optchar);
+ optopt = optchar;
+ return (BADARG);
+ } else /* white space */
+ place = nargv[optind];
+ optchar = parse_long_options(nargv, options, long_options,
+ idx, 0);
+ place = EMSG;
+ return (optchar);
+ }
+ if (*++oli != ':') { /* doesn't take argument */
+ if (!*place)
+ ++optind;
+ } else { /* takes (optional) argument */
+ optarg = NULL;
+ if (*place) /* no white space */
+ optarg = place;
+ else if (oli[1] != ':') { /* arg not optional */
+ if (++optind >= nargc) { /* no arg */
+ place = EMSG;
+ if (PRINT_ERROR)
+ warnx(recargchar, optchar);
+ optopt = optchar;
+ return (BADARG);
+ } else
+ optarg = nargv[optind];
+ }
+ place = EMSG;
+ ++optind;
+ }
+ /* dump back option letter */
+ return (optchar);
+}
+
+#ifdef REPLACE_GETOPT
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ *
+ * [eventually this will replace the BSD getopt]
+ */
+int
+getopt(int nargc, char * const *nargv, const char *options)
+{
+
+ /*
+ * We don't pass FLAG_PERMUTE to getopt_internal() since
+ * the BSD getopt(3) (unlike GNU) has never done this.
+ *
+ * Furthermore, since many privileged programs call getopt()
+ * before dropping privileges it makes sense to keep things
+ * as simple (and bug-free) as possible.
+ */
+ return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
+}
+#endif /* REPLACE_GETOPT */
+
+/*
+ * getopt_long --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt_long(int nargc, char * const *nargv, const char *options,
+ const struct option *long_options, int *idx)
+{
+
+ return (getopt_internal(nargc, nargv, options, long_options, idx,
+ FLAG_PERMUTE));
+}
+
+/*
+ * getopt_long_only --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt_long_only(int nargc, char * const *nargv, const char *options,
+ const struct option *long_options, int *idx)
+{
+
+ return (getopt_internal(nargc, nargv, options, long_options, idx,
+ FLAG_PERMUTE|FLAG_LONGONLY));
+} \ No newline at end of file
diff --git a/contrib/src/getopt/getopt.h b/contrib/src/getopt/getopt.h
new file mode 100644
index 0000000..8d526ab
--- /dev/null
+++ b/contrib/src/getopt/getopt.h
@@ -0,0 +1,95 @@
+#ifndef __GETOPT_H__
+/**
+ * DISCLAIMER
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is a part of the w64 mingw-runtime package.
+ *
+ * The w64 mingw-runtime package and its code is distributed in the hope that it
+ * will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR
+ * IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to
+ * warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#define __GETOPT_H__
+
+/* All the headers include this file. */
+#include <crtdefs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int optind; /* index of first non-option in argv */
+extern int optopt; /* single option character, as parsed */
+extern int opterr; /* flag to enable built-in diagnostics... */
+ /* (user may set to zero, to suppress) */
+
+extern char *optarg; /* pointer to argument of current option */
+
+extern int getopt(int nargc, char * const *nargv, const char *options);
+
+#ifdef _BSD_SOURCE
+/*
+ * BSD adds the non-standard `optreset' feature, for reinitialisation
+ * of `getopt' parsing. We support this feature, for applications which
+ * proclaim their BSD heritage, before including this header; however,
+ * to maintain portability, developers are advised to avoid it.
+ */
+# define optreset __mingw_optreset
+extern int optreset;
+#endif
+#ifdef __cplusplus
+}
+#endif
+/*
+ * POSIX requires the `getopt' API to be specified in `unistd.h';
+ * thus, `unistd.h' includes this header. However, we do not want
+ * to expose the `getopt_long' or `getopt_long_only' APIs, when
+ * included in this manner. Thus, close the standard __GETOPT_H__
+ * declarations block, and open an additional __GETOPT_LONG_H__
+ * specific block, only when *not* __UNISTD_H_SOURCED__, in which
+ * to declare the extended API.
+ */
+#endif /* !defined(__GETOPT_H__) */
+
+#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__)
+#define __GETOPT_LONG_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct option /* specification for a long form option... */
+{
+ const char *name; /* option name, without leading hyphens */
+ int has_arg; /* does it take an argument? */
+ int *flag; /* where to save its status, or NULL */
+ int val; /* its associated status value */
+};
+
+enum /* permitted values for its `has_arg' field... */
+{
+ no_argument = 0, /* option never takes an argument */
+ required_argument, /* option always requires an argument */
+ optional_argument /* option may take an argument */
+};
+
+extern int getopt_long(int nargc, char * const *nargv, const char *options,
+ const struct option *long_options, int *idx);
+extern int getopt_long_only(int nargc, char * const *nargv, const char *options,
+ const struct option *long_options, int *idx);
+/*
+ * Previous MinGW implementation had...
+ */
+#ifndef HAVE_DECL_GETOPT
+/*
+ * ...for the long form API only; keep this for compatibility.
+ */
+# define HAVE_DECL_GETOPT 1
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */ \ No newline at end of file
diff --git a/src/bindings/swig/php/uscxmlNativePHP.php b/src/bindings/swig/php/uscxmlNativePHP.php
index 668e01b..dccfbaf 100644
--- a/src/bindings/swig/php/uscxmlNativePHP.php
+++ b/src/bindings/swig/php/uscxmlNativePHP.php
@@ -2,7 +2,7 @@
/* ----------------------------------------------------------------------------
* This file was automatically generated by SWIG (http://www.swig.org).
- * Version 2.0.7
+ * Version 2.0.9
*
* This file is not intended to be easily readable and contains a number of
* coding conventions designed to improve portability and efficiency. Do not make
@@ -226,6 +226,42 @@ class Params {
}
}
+class Blob {
+ public $_cPtr=null;
+ protected $_pData=array();
+
+ function __set($var,$value) {
+ $func = 'Blob_'.$var.'_set';
+ if (function_exists($func)) return call_user_func($func,$this->_cPtr,$value);
+ if ($var === 'thisown') return swig_uscxmlNativePHP_alter_newobject($this->_cPtr,$value);
+ $this->_pData[$var] = $value;
+ }
+
+ function __isset($var) {
+ if (function_exists('Blob_'.$var.'_set')) return true;
+ if ($var === 'thisown') return true;
+ return array_key_exists($var, $this->_pData);
+ }
+
+ function __get($var) {
+ $func = 'Blob_'.$var.'_get';
+ if (function_exists($func)) return call_user_func($func,$this->_cPtr);
+ if ($var === 'thisown') return swig_uscxmlNativePHP_get_newobject($this->_cPtr);
+ return $this->_pData[$var];
+ }
+
+ function __construct($size_or_data,$size=null,$adopt=false) {
+ if (is_resource($size_or_data) && get_resource_type($size_or_data) === '_p_uscxml__Blob') {
+ $this->_cPtr=$size_or_data;
+ return;
+ }
+ switch (func_num_args()) {
+ case 1: $this->_cPtr=new_Blob($size_or_data); break;
+ default: $this->_cPtr=new_Blob($size_or_data,$size,$adopt);
+ }
+ }
+}
+
class Data {
public $_cPtr=null;
protected $_pData=array();
@@ -254,17 +290,16 @@ class Data {
const INTERPRETED = Data_INTERPRETED;
- const BINARY = Data_BINARY;
-
- function __construct($atom__or_dom=null,$type_=null) {
- if (is_resource($atom__or_dom) && get_resource_type($atom__or_dom) === '_p_uscxml__Data') {
- $this->_cPtr=$atom__or_dom;
+ function __construct($atom__or_data_or_dom=null,$type__or_size=null,$adopt=null) {
+ if (is_resource($atom__or_data_or_dom) && get_resource_type($atom__or_data_or_dom) === '_p_uscxml__Data') {
+ $this->_cPtr=$atom__or_data_or_dom;
return;
}
switch (func_num_args()) {
case 0: $this->_cPtr=new_Data(); break;
- case 1: $this->_cPtr=new_Data($atom__or_dom); break;
- default: $this->_cPtr=new_Data($atom__or_dom,$type_);
+ case 1: $this->_cPtr=new_Data($atom__or_data_or_dom); break;
+ case 2: $this->_cPtr=new_Data($atom__or_data_or_dom,$type__or_size); break;
+ default: $this->_cPtr=new_Data($atom__or_data_or_dom,$type__or_size,$adopt);
}
}
@@ -359,7 +394,6 @@ class Event {
}
function __get($var) {
- if ($var === 'namelist') return new StringMap(Event_namelist_get($this->_cPtr));
if ($var === 'data') return new Data(Event_data_get($this->_cPtr));
$func = 'Event_'.$var.'_get';
if (function_exists($func)) return call_user_func($func,$this->_cPtr);
@@ -502,18 +536,16 @@ class Event {
}
function getNameList() {
- $r=Event_getNameList($this->_cPtr);
- if (is_resource($r)) {
- $c=substr(get_resource_type($r), (strpos(get_resource_type($r), '__') ? strpos(get_resource_type($r), '__') + 2 : 3));
- if (class_exists($c)) return new $c($r);
- return new StringMap($r);
- }
- return $r;
+ return Event_getNameList($this->_cPtr);
}
function getParams() {
return Event_getParams($this->_cPtr);
}
+
+ static function getParam($params,$name,$target) {
+ return Event_getParam($params,$name,$target);
+ }
}
class InvokeRequest extends Event {
@@ -980,10 +1012,6 @@ class Interpreter {
return Interpreter_getProperAncestors($this->_cPtr,$s1,$s2);
}
- static function getUUID() {
- return Interpreter_getUUID();
- }
-
function getImpl() {
return Interpreter_getImpl($this->_cPtr);
}
diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp
index 7e61ed7..065b61e 100644
--- a/src/uscxml/Interpreter.cpp
+++ b/src/uscxml/Interpreter.cpp
@@ -1,3 +1,4 @@
+#include "uscxml/config.h"
#include "uscxml/Common.h"
#include "uscxml/Interpreter.h"
#include "uscxml/URL.h"
@@ -40,6 +41,145 @@ namespace uscxml {
using namespace Arabica::XPath;
using namespace Arabica::DOM;
+void InterpreterOptions::printUsageAndExit(const char* progName) {
+ printf("%s version " USCXML_VERSION " (" CMAKE_BUILD_TYPE " build - " CMAKE_COMPILER_STRING ")\n", progName);
+ printf("Usage\n");
+ printf("\t%s", progName);
+#ifdef BUILD_AS_PLUGINS
+ printf(" [-e pluginPath]");
+#endif
+ printf("[-v] [-pN] URL\n");
+ printf("\n");
+ printf("Options\n");
+ printf("\t-v : be verbose\n");
+ printf("\t-pN : port for HTTP server\n");
+ printf("\t-d : write each configuration as a dot file\n");
+ printf("\n");
+ exit(1);
+}
+
+unsigned int InterpreterOptions::getCapabilities() {
+ unsigned int capabilities = CAN_NOTHING;
+ if (withHTTP)
+ capabilities = capabilities | CAN_GENERIC_HTTP | CAN_BASIC_HTTP;
+
+ return capabilities;
+}
+
+InterpreterOptions InterpreterOptions::fromCmdLine(int argc, char** argv) {
+ InterpreterOptions options;
+ struct option longOptions[] = {
+ {"verbose", no_argument, 0, 'v'},
+ {"dot", no_argument, 0, 'd'},
+ {"port", required_argument, 0, 't'},
+ {"ssl-port", required_argument, 0, 's'},
+ {"certificate", required_argument, 0, 'c'},
+ {"private-key", required_argument, 0, 0},
+ {"public-key", required_argument, 0, 0},
+ {"plugin-path", required_argument, 0, 'p'},
+ {"loglevel", required_argument, 0, 'l'},
+ {"disable-http", no_argument, 0, 0},
+ {0, 0, 0, 0}
+ };
+
+ opterr = 0;
+ if (argc < 2) {
+ options.error = "No SCXML document to evaluate";
+ return options;
+ }
+
+ InterpreterOptions* currOptions = &options;
+
+ // parse global options
+ int optionInd = 0;
+ int option;
+ for (;;) {
+ option = getopt_long_only(argc, argv, "+vdt:s:c:p:l:", longOptions, &optionInd);
+ if (option == -1) {
+ if (optind == argc)
+ // we are done with parsing
+ goto DONE_PARSING_CMD;
+
+ std::string url = argv[optind];
+ options.interpreters[url] = new InterpreterOptions();
+ currOptions = options.interpreters[url];
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ if (argc <= 1)
+ goto DONE_PARSING_CMD;
+
+ }
+ switch(option) {
+ // cases without short option
+ case 0: {
+ if (boost::equals(longOptions[optionInd].name, "disable-http")) {
+ currOptions->withHTTP = false;
+ } else if (boost::equals(longOptions[optionInd].name, "private-key")) {
+ currOptions->privateKey = optarg;
+ } else if (boost::equals(longOptions[optionInd].name, "public-key")) {
+ currOptions->publicKey = optarg;
+ }
+ break;
+ }
+ // cases with short-hand options
+ case 'l':
+ currOptions->logLevel = strTo<unsigned int>(optarg);
+ break;
+ case 'p':
+ currOptions->pluginPath = optarg;
+ break;
+ case 'd':
+ currOptions->useDot = true;
+ break;
+ case 'c':
+ currOptions->certificate = optarg;
+ break;
+ case 't':
+ currOptions->httpPort = strTo<unsigned short>(optarg);
+ break;
+ case 's':
+ currOptions->httpsPort = strTo<unsigned short>(optarg);
+ break;
+ case 'v':
+ currOptions->verbose = true;
+ break;
+ case '?': {
+ std::string param = argv[optind - 1];
+ if (boost::starts_with(param, "--")) {
+ param = param.substr(2, param.length() - 2);
+ } else if (boost::starts_with(param, "-")) {
+ param = param.substr(1, param.length() - 1);
+ } else {
+ break;
+ }
+ boost::trim(param);
+
+ size_t equalPos = param.find("=");
+ if (equalPos != std::string::npos) {
+ std::string key = param.substr(0, equalPos);
+ std::string value = param.substr(equalPos + 1, param.length() - (equalPos + 1));
+ currOptions->additionalParameters[key] = value;
+ } else {
+ currOptions->additionalParameters[param] = "";
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+DONE_PARSING_CMD:
+
+ if (options.interpreters.size() == 0)
+ options.error = "No SCXML document to evaluate";
+
+ return options;
+}
+
std::map<std::string, boost::weak_ptr<InterpreterImpl> > Interpreter::_instances;
tthread::recursive_mutex Interpreter::_instanceMutex;
@@ -1761,26 +1901,15 @@ IOProcessor InterpreterImpl::getIOProcessor(const std::string& type) {
return _ioProcessors[type];
}
-void InterpreterImpl::setCmdLineOptions(int argc, char** argv) {
- char* key = NULL;
- char* value = NULL;
- for (int i = 0; i < argc; i++) {
- if (false) {
- } else if (strlen(argv[i]) > 2 && strncmp(&argv[i][0], "-", 1) == 0 && strncmp(&argv[i][1], "-", 1) == 0) {
- // longopt
- key = &argv[i][2];
- } else if (strlen(argv[i]) > 1 && strncmp(&argv[i][0], "-", 1) == 0 && strncmp(&argv[i][1], "-", 1) != 0) {
- // shortopt
- key = &argv[i][1];
- }
- if (key != NULL) {
- if (i + 1 < argc && strncmp(&argv[i + 1][0], "-", 1) != 0) {
- value = argv[++i];
- _cmdLineOptions.compound[key] = Data(value, Data::VERBATIM);
- } else {
- _cmdLineOptions.compound[key] = Data("true");
- }
+void InterpreterImpl::setCmdLineOptions(std::map<std::string, std::string> params) {
+ std::map<std::string, std::string>::iterator paramIter = params.begin();
+ while (paramIter != params.end()) {
+ if (paramIter->second.length() > 0) {
+ _cmdLineOptions.compound[paramIter->first] = Data(paramIter->second, Data::VERBATIM);
+ } else {
+ _cmdLineOptions.compound[paramIter->first] = Data("true");
}
+ paramIter++;
}
}
diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h
index aadef72..b8093ab 100644
--- a/src/uscxml/Interpreter.h
+++ b/src/uscxml/Interpreter.h
@@ -1,7 +1,10 @@
#ifndef RUNTIME_H_SQ1MBKGN
#define RUNTIME_H_SQ1MBKGN
+// this has to be the first include or MSVC will run amok
#include "uscxml/Common.h"
+#include "getopt.h"
+
#include "uscxml/URL.h"
#include <boost/algorithm/string.hpp>
@@ -61,6 +64,44 @@ enum Capabilities {
CAN_GENERIC_HTTP = 2,
};
+class InterpreterOptions {
+public:
+ bool useDot;
+ bool verbose;
+ bool withHTTP;
+ bool withHTTPS;
+ int logLevel;
+ unsigned short httpPort;
+ unsigned short httpsPort;
+ std::string pluginPath;
+ std::string certificate;
+ std::string privateKey;
+ std::string publicKey;
+ std::map<std::string, InterpreterOptions*> interpreters;
+ std::map<std::string, std::string> additionalParameters;
+
+ std::string error;
+
+ operator bool() {
+ return error.length() == 0;
+ }
+
+ static void printUsageAndExit(const char* progName);
+ static InterpreterOptions fromCmdLine(int argc, char** argv);
+ unsigned int getCapabilities();
+
+protected:
+ InterpreterOptions() :
+ useDot(false),
+ verbose(false),
+ withHTTP(true),
+ withHTTPS(true),
+ logLevel(0),
+ httpPort(8080),
+ httpsPort(8443)
+ {}
+};
+
class InterpreterImpl : public boost::enable_shared_from_this<InterpreterImpl> {
public:
@@ -100,7 +141,7 @@ public:
return _baseURI;
}
- void setCmdLineOptions(int argc, char** argv);
+ void setCmdLineOptions(std::map<std::string, std::string> params);
Data getCmdLineOptions() {
return _cmdLineOptions;
}
@@ -400,8 +441,8 @@ public:
return _impl->getNameSpaceInfo();
}
- void setCmdLineOptions(int argc, char** argv) {
- return _impl->setCmdLineOptions(argc, argv);
+ void setCmdLineOptions(std::map<std::string, std::string> params) {
+ return _impl->setCmdLineOptions(params);
}
Data getCmdLineOptions() {
return _impl->getCmdLineOptions();
diff --git a/src/uscxml/concurrency/eventqueue/DelayedEventQueue.cpp b/src/uscxml/concurrency/eventqueue/DelayedEventQueue.cpp
index cbb82eb..fe16361 100644
--- a/src/uscxml/concurrency/eventqueue/DelayedEventQueue.cpp
+++ b/src/uscxml/concurrency/eventqueue/DelayedEventQueue.cpp
@@ -26,14 +26,12 @@ DelayedEventQueue::~DelayedEventQueue() {
}
void DelayedEventQueue::run(void* instance) {
- DelayedEventQueue* THIS = (DelayedEventQueue*)instance;
+ DelayedEventQueue* INSTANCE = (DelayedEventQueue*)instance;
int result;
- while(THIS->_isStarted) {
- {
- //result = event_base_dispatch(THIS->_eventLoop);
- result = event_base_loop(THIS->_eventLoop, EVLOOP_NO_EXIT_ON_EMPTY);
- (void)result;
- }
+ while(INSTANCE->_isStarted) {
+ //result = event_base_dispatch(THIS->_eventLoop);
+ result = event_base_loop(INSTANCE->_eventLoop, EVLOOP_NO_EXIT_ON_EMPTY);
+ (void)result;
}
}
diff --git a/src/uscxml/concurrency/eventqueue/DelayedEventQueue.h b/src/uscxml/concurrency/eventqueue/DelayedEventQueue.h
index 0b72719..fa76c3f 100644
--- a/src/uscxml/concurrency/eventqueue/DelayedEventQueue.h
+++ b/src/uscxml/concurrency/eventqueue/DelayedEventQueue.h
@@ -19,9 +19,9 @@ class DelayedEventQueue {
public:
enum OpMask {
- FD_READ = EV_READ,
- FD_WRITE = EV_WRITE,
- FD_SIGNAL = EV_SIGNAL
+ DEQ_READ = EV_READ,
+ DEQ_WRITE = EV_WRITE,
+ DEQ_SIGNAL = EV_SIGNAL
};
struct callbackData {
diff --git a/src/uscxml/pch.h b/src/uscxml/pch.h
new file mode 100644
index 0000000..e4ae2d1
--- /dev/null
+++ b/src/uscxml/pch.h
@@ -0,0 +1,14 @@
+#include "uscxml/Common.h"
+
+#include <boost/algorithm/string.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include <iostream>
+#include <set>
+#include <map>
+#include <list>
+#include <vector>
+#include <string>
+
+#include <DOM/Document.hpp> \ No newline at end of file
diff --git a/src/uscxml/plugins/datamodel/CMakeLists.txt b/src/uscxml/plugins/datamodel/CMakeLists.txt
index 5fe82b7..3b6a852 100644
--- a/src/uscxml/plugins/datamodel/CMakeLists.txt
+++ b/src/uscxml/plugins/datamodel/CMakeLists.txt
@@ -1,63 +1,65 @@
-if (JSC_FOUND AND BUILD_DM_ECMA)
- set(USCXML_DATAMODELS "ecmascript(JSC) ${USCXML_DATAMODELS}")
- # JavaScriptCore ecmascript datamodel
- file(GLOB JSC_DATAMODEL
- ecmascript/JavaScriptCore/*.cpp
- ecmascript/JavaScriptCore/*.h
- ecmascript/*.cpp
- ecmascript/*.h
- )
- source_group("Datamodel\\jsc" FILES ${JSC_DATAMODEL})
- file(GLOB_RECURSE JSC_DOM
- ecmascript/JavaScriptCore/dom/*.cpp
- ecmascript/JavaScriptCore/dom/*.h
- )
- source_group("Datamodel\\DOM" FILES ${JSC_DOM})
- if (BUILD_AS_PLUGINS)
- add_library(
- datamodel_jsc SHARED
- ${JSC_DATAMODEL}
- ${JSC_DOM})
- target_link_libraries(datamodel_jsc
- uscxml
- ${JSC_LIBRARY})
- set_target_properties(datamodel_jsc PROPERTIES FOLDER "Plugin DataModel")
- else()
- list (APPEND USCXML_FILES ${JSC_DATAMODEL})
- list (APPEND USCXML_FILES ${JSC_DOM})
- list (APPEND USCXML_OPT_LIBS ${JSC_LIBRARY})
- endif()
-else()
-
-# GOOGLE V8 ecmascript datamodel
- set(USCXML_DATAMODELS "ecmascript(V8) ${USCXML_DATAMODELS}")
- # set(ENV{V8_SRC} ${CMAKE_SOURCE_DIR}/../v8)
- if (V8_FOUND AND BUILD_DM_ECMA)
- file(GLOB V8_DATAMODEL
- ecmascript/v8/*.cpp
- ecmascript/v8/*.h
+if (BUILD_DM_ECMA)
+ if (JSC_FOUND)
+ set(USCXML_DATAMODELS "ecmascript(JSC) ${USCXML_DATAMODELS}")
+ # JavaScriptCore ecmascript datamodel
+ file(GLOB JSC_DATAMODEL
+ ecmascript/JavaScriptCore/*.cpp
+ ecmascript/JavaScriptCore/*.h
ecmascript/*.cpp
ecmascript/*.h
)
- source_group("Datamodel\\v8" FILES ${V8_DATAMODEL})
- file(GLOB_RECURSE V8_DOM
- ecmascript/v8/dom/*.cpp
- ecmascript/v8/dom/*.h
+ source_group("Datamodel\\jsc" FILES ${JSC_DATAMODEL})
+ file(GLOB_RECURSE JSC_DOM
+ ecmascript/JavaScriptCore/dom/*.cpp
+ ecmascript/JavaScriptCore/dom/*.h
)
- source_group("Datamodel\\v8\\DOM" FILES ${V8_DOM})
-
+ source_group("Datamodel\\DOM" FILES ${JSC_DOM})
if (BUILD_AS_PLUGINS)
add_library(
- datamodel_v8 SHARED
- ${V8_DATAMODEL}
- ${V8_DOM})
- target_link_libraries(datamodel_v8
+ datamodel_jsc SHARED
+ ${JSC_DATAMODEL}
+ ${JSC_DOM})
+ target_link_libraries(datamodel_jsc
uscxml
- ${V8_LIBRARY})
- set_target_properties(datamodel_v8 PROPERTIES FOLDER "Plugin DataModel")
+ ${JSC_LIBRARY})
+ set_target_properties(datamodel_jsc PROPERTIES FOLDER "Plugin DataModel")
else()
- list (APPEND USCXML_FILES ${V8_DATAMODEL})
- list (APPEND USCXML_FILES ${V8_DOM})
+ list (APPEND USCXML_FILES ${JSC_DATAMODEL})
+ list (APPEND USCXML_FILES ${JSC_DOM})
+ list (APPEND USCXML_OPT_LIBS ${JSC_LIBRARY})
+ endif()
+ else()
+
+ # GOOGLE V8 ecmascript datamodel
+ set(USCXML_DATAMODELS "ecmascript(V8) ${USCXML_DATAMODELS}")
+ # set(ENV{V8_SRC} ${CMAKE_SOURCE_DIR}/../v8)
+ if (V8_FOUND AND BUILD_DM_ECMA)
+ file(GLOB V8_DATAMODEL
+ ecmascript/v8/*.cpp
+ ecmascript/v8/*.h
+ ecmascript/*.cpp
+ ecmascript/*.h
+ )
+ source_group("Datamodel\\v8" FILES ${V8_DATAMODEL})
+ file(GLOB_RECURSE V8_DOM
+ ecmascript/v8/dom/*.cpp
+ ecmascript/v8/dom/*.h
+ )
+ source_group("Datamodel\\v8\\DOM" FILES ${V8_DOM})
+
+ if (BUILD_AS_PLUGINS)
+ add_library(
+ datamodel_v8 SHARED
+ ${V8_DATAMODEL}
+ ${V8_DOM})
+ target_link_libraries(datamodel_v8
+ uscxml
+ ${V8_LIBRARY})
+ set_target_properties(datamodel_v8 PROPERTIES FOLDER "Plugin DataModel")
+ else()
+ list (APPEND USCXML_FILES ${V8_DATAMODEL})
+ list (APPEND USCXML_FILES ${V8_DOM})
+ endif()
endif()
endif()
endif()
diff --git a/src/uscxml/plugins/datamodel/ecmascript/TypedArray.h b/src/uscxml/plugins/datamodel/ecmascript/TypedArray.h
index 460afd4..e7d7e4c 100644
--- a/src/uscxml/plugins/datamodel/ecmascript/TypedArray.h
+++ b/src/uscxml/plugins/datamodel/ecmascript/TypedArray.h
@@ -1,6 +1,7 @@
#ifndef TYPEDARRAY_H_99815BLY
#define TYPEDARRAY_H_99815BLY
+#include "uscxml/Common.h"
#include "uscxml/Message.h"
#include <string>
diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DOM.h b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DOM.h
index 43b98ce..f35b13f 100644
--- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DOM.h
+++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DOM.h
@@ -1,6 +1,7 @@
#ifndef V8DOM_H_LKE1HKJK
#define V8DOM_H_LKE1HKJK
+#include "uscxml/Common.h"
#include "uscxml/Interpreter.h"
#include <v8.h>
#include <XPath/XPath.hpp>
diff --git a/src/uscxml/plugins/invoker/im/IMInvoker.cpp b/src/uscxml/plugins/invoker/im/IMInvoker.cpp
index cff9b5f..1e12650 100644
--- a/src/uscxml/plugins/invoker/im/IMInvoker.cpp
+++ b/src/uscxml/plugins/invoker/im/IMInvoker.cpp
@@ -7,12 +7,13 @@
#endif
#define GET_INSTANCE_IN_CALLBACK(account) \
-tthread::lock_guard<tthread::mutex> lock(_accountMutex); \
+tthread::lock_guard<tthread::recursive_mutex> lock(_accountMutex); \
+IMInvoker* inst = NULL;\
if (_accountInstances.find(account) == _accountInstances.end()) { \
LOG(ERROR) << "Callback for unknown account called"; \
- return; \
-} \
-IMInvoker* inst = _accountInstances[account];\
+} else {\
+ inst = _accountInstances[account];\
+}
namespace uscxml {
@@ -35,13 +36,19 @@ PurpleEventLoopUiOps IMInvoker::_uiEventLoopOps =
purpleEventTimeoutRemove,
purpleEventInputAdd,
purpleEventInputRemove,
- NULL, //purpleEventInputGetError,
+ purpleEventInputGetError,
purpleEventTimeoutAddSec,
NULL,
NULL,
NULL
};
-
+
+PurpleDebugUiOps IMInvoker::_uiDebugOps = {
+ purpleDebugPrint,
+ purpleDebugIsEnabled,
+ NULL, NULL, NULL, NULL
+};
+
PurpleAccountUiOps IMInvoker::_uiAccountOps = {
accountNotifyAdded,
accountStatusChanged,
@@ -181,7 +188,7 @@ PurpleWhiteboardUiOps IMInvoker::_uiWhiteboardOps = {
};
PurpleCoreUiOps IMInvoker::_uiCoreOps = {
- NULL,
+ purplePrefsInit,
NULL,
purpleUIInit,
NULL,
@@ -196,9 +203,39 @@ DelayedEventQueue* IMInvoker::_eventQueue = NULL;
tthread::mutex IMInvoker::_initMutex;
tthread::condition_variable IMInvoker::_initCond;
-tthread::mutex IMInvoker::_accountMutex;
+tthread::recursive_mutex IMInvoker::_accountMutex;
std::map<PurpleAccount*, IMInvoker*> IMInvoker::_accountInstances;
+
+void IMInvoker::setupPurpleSignals() {
+ int handle;
+ // connection signals
+ purple_signal_connect(purple_connections_get_handle(), "signed-on", &handle, PURPLE_CALLBACK(signedOnCB), NULL);
+
+ // conversation signals
+ purple_signal_connect(purple_conversations_get_handle(), "conversation-created", &handle, PURPLE_CALLBACK(conversationCreatedCB), NULL);
+ purple_signal_connect(purple_conversations_get_handle(), "chat-joined", &handle, PURPLE_CALLBACK(chatJoinedCB), NULL);
+ purple_signal_connect(purple_conversations_get_handle(), "chat-join-failed", &handle, PURPLE_CALLBACK(chatJoinFailedCB), NULL);
+ purple_signal_connect(purple_conversations_get_handle(), "buddy-typing", &handle, PURPLE_CALLBACK(buddyTypingCB), NULL);
+ purple_signal_connect(purple_conversations_get_handle(), "buddy-typed", &handle, PURPLE_CALLBACK(buddyTypedCB), NULL);
+ purple_signal_connect(purple_conversations_get_handle(), "buddy-typing-stopped", &handle, PURPLE_CALLBACK(buddyTypingStoppedCB), NULL);
+
+ // buddy signals
+ purple_signal_connect(purple_blist_get_handle(), "buddy-signed-on", &handle, PURPLE_CALLBACK(buddyEventCB), GINT_TO_POINTER(PURPLE_BUDDY_SIGNON));
+ purple_signal_connect(purple_blist_get_handle(), "buddy-signed-off", &handle, PURPLE_CALLBACK(buddyEventCB), GINT_TO_POINTER(PURPLE_BUDDY_SIGNOFF));
+ purple_signal_connect(purple_blist_get_handle(), "buddy-got-login-time", &handle, PURPLE_CALLBACK(buddyEventCB), GINT_TO_POINTER(PURPLE_BUDDY_SIGNON_TIME));
+ purple_signal_connect(purple_blist_get_handle(), "buddy-idle-changed", &handle, PURPLE_CALLBACK(buddyIdleChangedCB), NULL);
+ purple_signal_connect(purple_blist_get_handle(), "buddy-status-changed", &handle, PURPLE_CALLBACK(buddyStatusChangedCB), NULL);
+ purple_signal_connect(purple_blist_get_handle(), "buddy-icon-changed", &handle, PURPLE_CALLBACK(buddyEventCB), GINT_TO_POINTER(PURPLE_BUDDY_ICON));
+ purple_signal_connect(purple_blist_get_handle(), "buddy-added", &handle, PURPLE_CALLBACK(buddyAddedCB), NULL);
+ purple_signal_connect(purple_blist_get_handle(), "buddy-removed", &handle, PURPLE_CALLBACK(buddyRemovedCB), NULL);
+ purple_signal_connect(purple_blist_get_handle(), "blist-node-aliased", &handle, PURPLE_CALLBACK(blistNodeAliasedCB), NULL);
+ purple_signal_connect(purple_blist_get_handle(), "buddy-caps-changed", &handle, PURPLE_CALLBACK(buddyCapsChangedCB), NULL);
+
+ // xfer signals
+ purple_signal_connect(purple_xfers_get_handle(), "file-recv-request", &handle, PURPLE_CALLBACK(fileRecvRequestCB), NULL);
+}
+
void IMInvoker::initLibPurple(void *userdata, const std::string event) {
_initMutex.lock();
@@ -218,7 +255,6 @@ void IMInvoker::initLibPurple(void *userdata, const std::string event) {
purple_debug_set_enabled(false);
purple_core_set_ui_ops(&_uiCoreOps);
-// purple_eventloop_set_ui_ops(&glib_eventloops);
purple_eventloop_set_ui_ops(&_uiEventLoopOps);
purple_plugins_add_search_path("/usr/local/lib/purple-3");
@@ -257,64 +293,153 @@ void IMInvoker::initLibPurple(void *userdata, const std::string event) {
_initMutex.unlock();
_initCond.notify_all();
+}
+// purple event callbacks
+void IMInvoker::signedOnCB(PurpleConnection *gc, gpointer null) {
+ PurpleAccount *account = purple_connection_get_account(gc);
+ GET_INSTANCE_IN_CALLBACK(account);
+ if (!inst)
+ return;
+
+#if 0
+ GSList *buddies = purple_find_buddies(purple_connection_get_account(gc), NULL);
+ GSList *cur;
+ for (cur = buddies; cur; cur = cur->next) {
+ buddyAddedCB((PurpleBuddy *)cur->data);
+ }
+ g_slist_free(buddies);
+#endif
+
+ // set my status to active
+ PurpleSavedStatus* status = purple_savedstatus_new(NULL, PURPLE_STATUS_AVAILABLE);
+ purple_savedstatus_activate(status);
+
+ Event retEv("im.signed.on");
+ inst->returnEvent(retEv);
}
-void IMInvoker::buddyStatusChangedCB(PurpleBuddy *buddy, PurpleStatus *old, PurpleStatus *newstatus) {
+void IMInvoker::conversationCreatedCB(PurpleConversation *conv, void *data) {}
+void IMInvoker::chatJoinedCB(PurpleConversation *conv, void *data) {}
+void IMInvoker::chatJoinFailedCB(PurpleConnection *gc, GHashTable *components) {}
+void IMInvoker::buddyTypingCB(PurpleAccount *account, const char *name, void *data) {}
+void IMInvoker::buddyTypedCB(PurpleAccount *account, const char *name, void *data) {}
+void IMInvoker::buddyTypingStoppedCB(PurpleAccount *account, const char *name, void *data) {}
+
+void IMInvoker::buddyEventCB(PurpleBuddy *buddy, PurpleBuddyEvent event) {
+ if (!buddy)
+ return;
+
PurpleAccount *account = purple_buddy_get_account(buddy);
GET_INSTANCE_IN_CALLBACK(account);
+ if (!inst)
+ return;
+
+ switch (event) {
+ case PURPLE_BUDDY_SIGNOFF:
+ case PURPLE_BUDDY_SIGNON: {
+ PurplePresence* presence = purple_buddy_get_presence(buddy);
+ PurpleStatus* status = purple_presence_get_active_status(presence);
+ buddyStatusChangedCB(buddy, NULL, status, event);
+ break;
+ }
+ case PURPLE_BUDDY_ICON:
+ break;
+
+ default:
+ break;
+ }
- std::string buddyName = purple_buddy_get_name(buddy);
- inst->_dataModelVars.compound["buddies"].compound[buddyName] = buddyToData(buddy);
}
-void IMInvoker::buddyIdleChangeCB(PurpleBuddy *buddy, gboolean old_idle, gboolean idle) {
+void IMInvoker::buddyIdleChangedCB(PurpleBuddy *buddy, gboolean old_idle, gboolean idle, PurpleBuddyEvent event) {
+}
+
+void IMInvoker::buddyStatusChangedCB(PurpleBuddy *buddy, PurpleStatus *old, PurpleStatus *newstatus, PurpleBuddyEvent event) {
PurpleAccount *account = purple_buddy_get_account(buddy);
GET_INSTANCE_IN_CALLBACK(account);
-}
+
+ std::string buddyName = purple_buddy_get_name(buddy);
+ Data buddyData = buddyToData(buddy);
+ inst->_dataModelVars.compound["buddies"].compound[buddyName] = buddyData;
+
+ Event retEv("im.buddy.status.changed");
+ retEv.data = buddyData;
+ inst->returnEvent(retEv);
-void IMInvoker::buddyUpdateIdleCB() {
}
void IMInvoker::buddyAddedCB(PurpleBuddy* buddy) {
PurpleAccount *account = purple_buddy_get_account(buddy);
GET_INSTANCE_IN_CALLBACK(account);
+ if (!inst)
+ return;
+
+ std::string buddyName = purple_buddy_get_name(buddy);
+
+ Event retEv("im.buddy.added");
+ retEv.data.compound["name"] = Data(buddyName, Data::VERBATIM);
+ inst->returnEvent(retEv);
+
+ buddyStatusChangedCB(buddy, NULL, purple_presence_get_active_status(purple_buddy_get_presence(buddy)), PURPLE_BUDDY_NONE);
+
}
void IMInvoker::buddyRemovedCB(PurpleBuddy* buddy) {
PurpleAccount *account = purple_buddy_get_account(buddy);
GET_INSTANCE_IN_CALLBACK(account);
+ std::string buddyName = purple_buddy_get_name(buddy);
+
+ Event retEv("im.buddy.removed");
+ retEv.data.compound["name"] = Data(buddyName, Data::VERBATIM);
+ inst->returnEvent(retEv);
+
+ inst->_dataModelVars.compound["buddies"].compound.erase(buddyName);
+
}
-void IMInvoker::buddyCapsChangedCB(PurpleBuddy* buddy, PurpleMediaCaps newcaps, PurpleMediaCaps oldcaps) {
- PurpleAccount *account = purple_buddy_get_account(buddy);
- GET_INSTANCE_IN_CALLBACK(account);
+void IMInvoker::blistNodeAliasedCB(PurpleBlistNode *node, char *old_alias) {
}
-gboolean IMInvoker::jabberRcvdPresenceCB(PurpleConnection *gc, const char *type, const char *from, xmlnode *presence) {
- PurpleAccount *account = purple_connection_get_account(gc);
- GET_INSTANCE_IN_CALLBACK(account);
+void IMInvoker::fileRecvRequestCB(PurpleXfer *xfer) {
+ purple_xfer_set_local_filename(xfer, "");
}
-void IMInvoker::buddySignOnOffCB(PurpleBuddy *buddy) {
+
+void IMInvoker::buddyCapsChangedCB(PurpleBuddy* buddy, PurpleMediaCaps newcaps, PurpleMediaCaps oldcaps) {
PurpleAccount *account = purple_buddy_get_account(buddy);
- tthread::lock_guard<tthread::mutex> lock(_accountMutex);
- if (_accountInstances.find(account) == _accountInstances.end()) {
- LOG(ERROR) << "Callback for unknown account called";
- return;
- }
- IMInvoker* inst = _accountInstances[account];
-
- std::string buddyName = purple_buddy_get_name(buddy);
- inst->_dataModelVars.compound["buddies"].compound[buddyName] = buddyToData(buddy);
+ GET_INSTANCE_IN_CALLBACK(account);
}
-void IMInvoker::signedOnCB(PurpleConnection *gc, gpointer null) {
- PurpleSavedStatus* status = purple_savedstatus_new(NULL, PURPLE_STATUS_AVAILABLE);
- purple_savedstatus_activate(status);
+Data IMInvoker::statusToData(PurpleStatus *status) {
+ Data data;
+ const char* statusName = purple_status_get_name(status);
+ if (statusName) data.compound["name"] = Data(statusName, Data::VERBATIM);
+
+ PurpleStatusType* statusType = purple_status_get_type(status);
+
+ GList *statusAttrElem;
+ GList *statusAttrList = purple_status_type_get_attrs(statusType);
+ PurpleStatusAttr* statusAttr;
+ for(statusAttrElem = statusAttrList; statusAttrElem; statusAttrElem = statusAttrElem->next) {
+ statusAttr = (PurpleStatusAttr*)statusAttrElem->data;
+ const char* statusAttrId = purple_status_attr_get_id(statusAttr);
+ PurpleValue* statusValue = purple_status_get_attr_value(status, statusAttrId);
+ if (statusValue) {
+ data.compound[statusAttrId] = purpleValueToData(statusValue);
+ }
+ }
+
+ data.compound["active"] = Data((bool)purple_status_is_active(status));
+ data.compound["available"] = Data((bool)purple_status_is_available(status));
+ data.compound["exclusive"] = Data((bool)purple_status_is_exclusive(status));
+ data.compound["active"] = Data((bool)purple_status_is_active(status));
+ data.compound["independent"] = Data((bool)purple_status_is_independent(status));
+ data.compound["online"] = Data((bool)purple_status_is_online(status));
+
+ return data;
}
-
Data IMInvoker::buddyToData(PurpleBuddy *buddy) {
Data data;
std::string buddyName = purple_buddy_get_name(buddy);
@@ -346,53 +471,16 @@ Data IMInvoker::buddyToData(PurpleBuddy *buddy) {
for(statusElem = statusList; statusElem; statusElem = statusElem->next) {
status = (PurpleStatus*)statusElem->data;
const char* statusId = purple_status_get_id(status);
- const char* statusName = purple_status_get_name(status);
PurpleStatusPrimitive statusPrimitive = purple_primitive_get_type_from_id(statusId);
-
+
// only include active states
if(statusPrimitive == PURPLE_STATUS_UNSET || !purple_presence_is_status_primitive_active(presence, statusPrimitive))
continue;
-
- if (statusName) data.compound["status"].compound[statusId] = Data(statusName, Data::VERBATIM);
-
- PurpleStatusType* statusType = purple_status_get_type(status);
-
- GList *statusAttrElem;
- GList *statusAttrList = purple_status_type_get_attrs(statusType);
- PurpleStatusAttr* statusAttr;
- for(statusAttrElem = statusAttrList; statusAttrElem; statusAttrElem = statusAttrElem->next) {
- statusAttr = (PurpleStatusAttr*)statusAttrElem->data;
- const char* statusAttrId = purple_status_attr_get_id(statusAttr);
- const char* statusAttrName = purple_status_attr_get_name(statusAttr);
-
- PurpleValue* statusAttrValue = purple_status_attr_get_value(statusAttr);
- if (statusAttrValue) {
- Data purpleValue = purpleValueToData(statusAttrValue);
- if (purpleValue) {
- data.compound["status"].compound[statusId].compound[statusAttrId].compound["value"] = purpleValue;
- if (statusAttrName) {
- data.compound["status"].compound[statusId].compound[statusAttrId].compound["name"] = Data(statusAttrName, Data::VERBATIM);
- }
- }
- }
- }
-
- data.compound["status"].compound[statusId].compound["active"] = Data((bool)purple_status_is_active(status));
- data.compound["status"].compound[statusId].compound["available"] = Data((bool)purple_status_is_available(status));
- data.compound["status"].compound[statusId].compound["exclusive"] = Data((bool)purple_status_is_exclusive(status));
- data.compound["status"].compound[statusId].compound["active"] = Data((bool)purple_status_is_active(status));
- data.compound["status"].compound[statusId].compound["independent"] = Data((bool)purple_status_is_independent(status));
- data.compound["status"].compound[statusId].compound["online"] = Data((bool)purple_status_is_online(status));
-
-
- PurpleValue* statusValue = purple_status_get_attr_value(status, statusId);
- if (statusValue)
- data.compound["status"].compound[statusId].compound["value"] = purpleValueToData(statusValue);
-
+ data.compound["status"].compound[statusId] = statusToData(status);
}
}
- std::cout << Data::toJSON(data);
+
return data;
}
@@ -407,7 +495,6 @@ Data IMInvoker::purpleValueToData(PurpleValue* value) {
case PURPLE_TYPE_STRING:
if (purple_value_get_string(value)) {
data = Data(purple_value_get_string(value), Data::VERBATIM);
- std::cout << purple_value_get_string(value) << std::endl;
}
break;
case PURPLE_TYPE_CHAR:
@@ -480,7 +567,7 @@ boost::shared_ptr<InvokerImpl> IMInvoker::create(InterpreterImpl* interpreter) {
}
Data IMInvoker::getDataModelVariables() {
- tthread::lock_guard<tthread::mutex> lock(_accountMutex);
+ tthread::lock_guard<tthread::recursive_mutex> lock(_accountMutex);
return _dataModelVars;
}
@@ -497,7 +584,7 @@ void IMInvoker::send(const SendRequest& req) {
void IMInvoker::send(void *userdata, const std::string event) {
// we are in the thread that manages all of libpurple
EventContext* ctx = (EventContext*)userdata;
-#if 0
+
if (boost::iequals(ctx->sendReq.name, "im.send")) {
if (ctx->instance->_account) {
std::string receiver;
@@ -510,7 +597,6 @@ void IMInvoker::send(void *userdata, const std::string event) {
PurpleConversation* conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, ctx->instance->_account, receiver.c_str());
purple_conv_im_send(purple_conversation_get_im_data(conv), ctx->sendReq.content.c_str());
-#if 0
if (data.binary) {
PurpleConnection *gc = purple_account_get_connection(ctx->instance->_account);
PurplePlugin *prpl;
@@ -521,18 +607,30 @@ void IMInvoker::send(void *userdata, const std::string event) {
prpl = purple_connection_get_prpl(gc);
prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
-// if (prpl_info->send_file &&
-// (prpl_info->can_receive_file
-// && prpl_info->can_receive_file(gc, receiver.c_str())))
-// prpl_info->send_file(gc, receiver.c_str(), file);
- prpl_info->send_raw(gc, data.binary->_data, data.binary->_size);
+// if (prpl_info && prpl_info->new_xfer) {
+// PurpleXfer* xfer = (prpl_info->new_xfer)(purple_account_get_connection(ctx->instance->_account), receiver.c_str());
+// purple_xfer_set_local_filename(xfer, "/Users/sradomski/Documents/W3C Standards.pdf");
+// purple_xfer_set_filename(xfer, "asdfadsf.pdf");
+// purple_xfer_request(xfer);
+// purple_xfer_request_accepted(xfer, "/Users/sradomski/Documents/W3C Standards.pdf");
+// }
+
+ //Set the filename
+// purple_xfer_set_local_filename(xfer, [[fileTransfer localFilename] UTF8String]);
+// purple_xfer_set_filename(xfer, [[[fileTransfer localFilename] lastPathComponent] UTF8String]);
+// xfer->ui_data
+// purple_xfer_request(xfer);
+
+ serv_send_file(gc, "sradomski@localhost", "/Users/sradomski/Documents/W3C Standards.pdf");
+// if (prpl_info->send_file && (prpl_info->can_receive_file && prpl_info->can_receive_file(gc, receiver.c_str()))) {
+// prpl_info->send_file(gc, receiver.c_str(), "/Users/sradomski/Documents/W3C Standards.pdf");
+// }
+// prpl_info->send_raw(gc, data.binary->data, data.binary->size);
}
}
-#endif
}
}
-#endif
delete(ctx);
}
@@ -565,23 +663,8 @@ void IMInvoker::invoke(void *userdata, const std::string event) {
_accountInstances[instance->_account] = instance;
purple_account_set_password(instance->_account, password.c_str(), NULL, NULL);
-
purple_account_set_enabled(instance->_account, "uscxml", true);
- int handle;
- purple_signal_connect(purple_connections_get_handle(), "signed-on", &handle, PURPLE_CALLBACK(signedOnCB), NULL);
-
- purple_signal_connect(purple_blist_get_handle(), "buddy-signed-on", &handle, PURPLE_CALLBACK(buddySignOnOffCB), NULL);
- purple_signal_connect(purple_blist_get_handle(), "buddy-signed-off", &handle, PURPLE_CALLBACK(buddySignOnOffCB), NULL);
- purple_signal_connect(purple_blist_get_handle(), "buddy-status-changed", &handle, PURPLE_CALLBACK(buddyStatusChangedCB), NULL);
-
- purple_signal_connect(purple_blist_get_handle(), "buddy-idle-changed", &handle, PURPLE_CALLBACK(buddyIdleChangeCB), NULL);
- purple_signal_connect(purple_blist_get_handle(), "update-idle", &handle, PURPLE_CALLBACK(buddyUpdateIdleCB), NULL);
- purple_signal_connect(purple_blist_get_handle(), "buddy-added", &handle, PURPLE_CALLBACK(buddyAddedCB), NULL);
- purple_signal_connect(purple_blist_get_handle(), "buddy-removed", &handle, PURPLE_CALLBACK(buddyRemovedCB), NULL);
- purple_signal_connect(purple_blist_get_handle(), "buddy-caps-changed", &handle, PURPLE_CALLBACK(buddyCapsChangedCB), NULL);
- purple_signal_connect(purple_blist_get_handle(), "jabber-receiving-presence", &handle, PURPLE_CALLBACK(jabberRcvdPresenceCB), NULL);
-
delete(ctx);
_accountMutex.unlock();
}
@@ -616,24 +699,65 @@ guint IMInvoker::purpleEventInputAdd(int fd, PurpleInputCondition cond, PurpleIn
short opMask = 0;
if (cond & PURPLE_INPUT_READ)
- opMask |= DelayedEventQueue::FD_READ;
+ opMask |= DelayedEventQueue::DEQ_READ;
if (cond & PURPLE_INPUT_WRITE)
- opMask |= DelayedEventQueue::FD_WRITE;
+ opMask |= DelayedEventQueue::DEQ_WRITE;
guint eventId = g_rand_int(_gRand);
+// std::cout << "-- Input add " << eventId << " --------" << fd << std::endl;
_eventQueue->addEvent(toStr(eventId), fd, opMask, purpleCallback, ctx, true);
return eventId;
}
gboolean IMInvoker::purpleEventInputRemove(guint handle) {
+// std::cout << "-- Input del " << handle << std::endl;
_eventQueue->cancelEvent(toStr(handle));
return true;
}
int IMInvoker::purpleEventInputGetError(int fd, int *error) {
- // unused
- std::cout << "purpleEventInputGetError" << std::endl;
- return 0;
+ int ret;
+ socklen_t len;
+ len = sizeof(*error);
+
+ ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, error, &len);
+ if (!ret && !(*error)) {
+ /*
+ * Taken from Fire's FaimP2PConnection.m:
+ * The job of this function is to detect if the connection failed or not
+ * There has to be a better way to do this
+ *
+ * Any socket that fails to connect will select for reading and writing
+ * and all reads and writes will fail
+ * Any listening socket will select for reading, and any read will fail
+ * So, select for writing, if you can write, and the write fails, not connected
+ */
+
+ {
+ fd_set thisfd;
+ struct timeval timeout;
+
+ FD_ZERO(&thisfd);
+ FD_SET(fd, &thisfd);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ select(fd+1, NULL, &thisfd, NULL, &timeout);
+ if(FD_ISSET(fd, &thisfd)){
+ ssize_t length = 0;
+ char buffer[4] = {0, 0, 0, 0};
+
+ length = write(fd, buffer, length);
+ if(length == -1)
+ {
+ /* Not connected */
+ ret = -1;
+ *error = ENOTCONN;
+ }
+ }
+ }
+ }
+
+ return ret;
}
void IMInvoker::purpleCallback(void *userdata, const std::string event) {
@@ -642,16 +766,20 @@ void IMInvoker::purpleCallback(void *userdata, const std::string event) {
ctx->function(ctx->data);
delete ctx;
} else if(ctx->input) {
+// std::cout << "operating on " << ctx->inputFD << std::endl;
ctx->input(ctx->data, ctx->inputFD, ctx->cond);
}
}
-void IMInvoker::purplePrefsInit(void) {}
+void IMInvoker::purplePrefsInit(void) {
+ purple_prefs_add_bool("/auto-login", false);
+}
+
void IMInvoker::purpleDebugInit(void) {}
void IMInvoker::purpleUIInit(void) {
purple_accounts_set_ui_ops(&_uiAccountOps);
- purple_xfers_set_ui_ops(&_uiXferOps);
+// purple_xfers_set_ui_ops(&_uiXferOps);
// purple_blist_set_ui_ops(&_uiBuddyOps);
// purple_notify_set_ui_ops(&_uiNotifyOps);
// purple_privacy_set_ui_ops(&_uiPrivacyOps);
@@ -659,6 +787,10 @@ void IMInvoker::purpleUIInit(void) {
// purple_connections_set_ui_ops(&_uiConnectOps);
// purple_whiteboard_set_ui_ops(&_uiWhiteboardOps);
purple_conversations_set_ui_ops(&_uiConvOps);
+ purple_debug_set_ui_ops(&_uiDebugOps);
+
+ setupPurpleSignals();
+
}
void IMInvoker::purpleQuit(void) {}
@@ -697,7 +829,7 @@ void* IMInvoker::accountRequestAuthorize(PurpleAccount *account,
PurpleAccountRequestAuthorizationCb authorize_cb,
PurpleAccountRequestAuthorizationCb deny_cb,
void *user_data) {
- // always accept all requests
+ // always accept all "may I add you as a buddy?" requests
authorize_cb(message, user_data);
return user_data;
}
@@ -788,9 +920,11 @@ void IMInvoker::purpleCancelRemote(PurpleXfer *xfer) {
}
gssize IMInvoker::purpleWrite(PurpleXfer *xfer, const guchar *buffer, gssize size) {
std::cout << "purpleWrite" << std::endl;
+ return 0;
}
gssize IMInvoker::purpleRead(PurpleXfer *xfer, guchar **buffer, gssize size) {
std::cout << "purpleRead" << std::endl;
+ return 0;
}
void IMInvoker::purpleDataNotSent(PurpleXfer *xfer, const guchar *buffer, gsize size) {
std::cout << "purpleDataNotSent" << std::endl;
@@ -837,34 +971,66 @@ void* IMInvoker::purpleRequestInput(const char *title, const char *primary,
gboolean multiline, gboolean masked, gchar *hint,
const char *ok_text, GCallback ok_cb,
const char *cancel_text, GCallback cancel_cb,
- PurpleRequestCommonParameters *cpar, void *user_data) {}
+ PurpleRequestCommonParameters *cpar, void *user_data) {
+ return NULL;
+}
void* IMInvoker::purpleRequestChoice(const char *title, const char *primary,
const char *secondary, gpointer default_value,
const char *ok_text, GCallback ok_cb, const char *cancel_text,
GCallback cancel_cb, PurpleRequestCommonParameters *cpar,
- void *user_data, va_list choices) {}
+ void *user_data, va_list choices) {
+ return NULL;
+}
void* IMInvoker::purpleRequestAction(const char *title, const char *primary,
const char *secondary, int default_action,
PurpleRequestCommonParameters *cpar, void *user_data,
- size_t action_count, va_list actions) {}
+ size_t action_count, va_list actions) {
+ return NULL;
+}
void* IMInvoker::purpleRequestWait(const char *title, const char *primary,
const char *secondary, gboolean with_progress,
PurpleRequestCancelCb cancel_cb,
- PurpleRequestCommonParameters *cpar, void *user_data) {}
+ PurpleRequestCommonParameters *cpar, void *user_data) {
+ return NULL;
+}
+
+void IMInvoker::purpleRequestWaitUpdate(void *ui_handle, gboolean pulse, gfloat fraction) {
-void IMInvoker::purpleRequestWaitUpdate(void *ui_handle, gboolean pulse, gfloat fraction) {}
+}
void* IMInvoker::purpleRequestFields(const char *title, const char *primary,
const char *secondary, PurpleRequestFields *fields,
const char *ok_text, GCallback ok_cb,
const char *cancel_text, GCallback cancel_cb,
- PurpleRequestCommonParameters *cpar, void *user_data) {}
+ PurpleRequestCommonParameters *cpar, void *user_data) {
+ return NULL;
+}
void* IMInvoker::purpleRequestFile(const char *title, const char *filename,
gboolean savedialog, GCallback ok_cb, GCallback cancel_cb,
- PurpleRequestCommonParameters *cpar, void *user_data) {}
+ PurpleRequestCommonParameters *cpar, void *user_data) {
+ // click ok
+ PurpleXfer *xfer = (PurpleXfer *)user_data;
+ PurpleXferType xferType = purple_xfer_get_type(xfer);
+ if (xferType == PURPLE_XFER_RECEIVE) {
+ ((PurpleRequestFileCb)ok_cb)(user_data, filename);
+ } else if (xferType == PURPLE_XFER_SEND) {
+ if (xfer->local_filename != NULL && xfer->filename != NULL) {
+ ((PurpleRequestFileCb)ok_cb)(user_data, xfer->local_filename);
+ } else {
+ ((PurpleRequestFileCb)cancel_cb)(user_data, xfer->local_filename);
+ }
+ }
+ return NULL;
+}
+
void* IMInvoker::purpleRequestFolder(const char *title, const char *dirname,
GCallback ok_cb, GCallback cancel_cb,
- PurpleRequestCommonParameters *cpar, void *user_data) {}
-void IMInvoker::purpleRequestClose(PurpleRequestType type, void *ui_handle) {}
+ PurpleRequestCommonParameters *cpar, void *user_data) {
+ return NULL;
+}
+
+void IMInvoker::purpleRequestClose(PurpleRequestType type, void *ui_handle) {
+
+}
// connection ui operations
@@ -885,4 +1051,14 @@ void IMInvoker::purpleDrawPont(PurpleWhiteboard *wb, int x, int y, int color, in
void IMInvoker::purpleDrawLine(PurpleWhiteboard *wb, int x1, int y1, int x2, int y2, int color, int size) {}
void IMInvoker::purpleClearWB(PurpleWhiteboard *wb) {}
+// debug ui operations
+void IMInvoker::purpleDebugPrint(PurpleDebugLevel level, const char *category, const char *arg_s) {
+// std::cout << category << ": " << arg_s << std::endl;
+}
+
+gboolean IMInvoker::purpleDebugIsEnabled(PurpleDebugLevel level, const char *category) {
+ return true;
+}
+
+
} \ No newline at end of file
diff --git a/src/uscxml/plugins/invoker/im/IMInvoker.h b/src/uscxml/plugins/invoker/im/IMInvoker.h
index b8a57f6..51af8f8 100644
--- a/src/uscxml/plugins/invoker/im/IMInvoker.h
+++ b/src/uscxml/plugins/invoker/im/IMInvoker.h
@@ -13,6 +13,20 @@ extern "C" {
namespace uscxml {
+typedef enum {
+ PURPLE_BUDDY_NONE = 0x00, /**< No events. */
+ PURPLE_BUDDY_SIGNON = 0x01, /**< The buddy signed on. */
+ PURPLE_BUDDY_SIGNOFF = 0x02, /**< The buddy signed off. */
+ PURPLE_BUDDY_INFO_UPDATED = 0x10, /**< The buddy's information (profile) changed. */
+ PURPLE_BUDDY_ICON = 0x40, /**< The buddy's icon changed. */
+ PURPLE_BUDDY_MISCELLANEOUS = 0x80, /**< The buddy's service-specific miscalleneous info changed. */
+ PURPLE_BUDDY_SIGNON_TIME = 0x11, /**< The buddy's signon time changed. */
+ PURPLE_BUDDY_EVIL = 0x12, /**< The buddy's warning level changed. */
+ PURPLE_BUDDY_DIRECTIM_CONNECTED = 0x14, /**< Connected to the buddy via DirectIM. */
+ PURPLE_BUDDY_DIRECTIM_DISCONNECTED = 0x18, /**< Disconnected from the buddy via DirectIM. */
+ PURPLE_BUDDY_NAME = 0x20 /**<Buddy name (UID) changed. */
+} PurpleBuddyEvent;
+
class IMInvoker : public InvokerImpl {
public:
struct EventContext {
@@ -38,13 +52,14 @@ public:
virtual void cancel(const std::string sendId);
virtual void invoke(const InvokeRequest& req);
-protected:
+private:
static bool _libPurpleIsInitialized;
static Data _pluginData;
Data _dataModelVars;
static Data buddyToData(PurpleBuddy *buddy);
+ static Data statusToData(PurpleStatus *status);
static Data purpleValueToData(PurpleValue* value);
static PurpleAccountUiOps _uiAccountOps;
@@ -58,31 +73,39 @@ protected:
static PurpleRequestUiOps _uiRequestOps;
static PurpleConnectionUiOps _uiConnectOps;
static PurpleWhiteboardUiOps _uiWhiteboardOps;
+ static PurpleDebugUiOps _uiDebugOps;
static PurpleRequestFeature _features;
static GHashTable* _uiInfo;
static GRand* _gRand;
- static tthread::mutex _accountMutex;
+ static tthread::recursive_mutex _accountMutex;
static std::map<PurpleAccount*, IMInvoker*> _accountInstances;
static tthread::mutex _initMutex;
static tthread::condition_variable _initCond;
static DelayedEventQueue* _eventQueue;
- // event callbacks
+ // libpurple event callbacks
static void signedOnCB(PurpleConnection *gc, gpointer null);
- static void buddySignOnOffCB(PurpleBuddy *buddy);
- static void buddyStatusChangedCB(PurpleBuddy *buddy, PurpleStatus *oldstatus, PurpleStatus *newstatus);
- static void buddyIdleChangeCB(PurpleBuddy *buddy, gboolean old_idle, gboolean idle);
- static void buddyUpdateIdleCB();
+ static void conversationCreatedCB(PurpleConversation *conv, void *data);
+ static void chatJoinedCB(PurpleConversation *conv, void *data);
+ static void chatJoinFailedCB(PurpleConnection *gc, GHashTable *components);
+ static void buddyTypingCB(PurpleAccount *account, const char *name, void *data);
+ static void buddyTypedCB(PurpleAccount *account, const char *name, void *data);
+ static void buddyTypingStoppedCB(PurpleAccount *account, const char *name, void *data);
+ static void buddyIdleChangedCB(PurpleBuddy *buddy, gboolean old_idle, gboolean idle, PurpleBuddyEvent event);
+ static void blistNodeAliasedCB(PurpleBlistNode *node, char *old_alias);
+ static void buddyEventCB(PurpleBuddy *buddy, PurpleBuddyEvent event);
+ static void buddyStatusChangedCB(PurpleBuddy *buddy, PurpleStatus *oldstatus, PurpleStatus *newstatus, PurpleBuddyEvent event);
static void buddyAddedCB(PurpleBuddy* buddy);
static void buddyRemovedCB(PurpleBuddy* buddy);
+ static void fileRecvRequestCB(PurpleXfer *xfer);
static void buddyCapsChangedCB(PurpleBuddy* buddy, PurpleMediaCaps newcaps, PurpleMediaCaps oldcaps);
- static gboolean jabberRcvdPresenceCB(PurpleConnection *gc, const char *type, const char *from, xmlnode *presence);
-
// these are only being called from the delayed queue's thread
static void initLibPurple(void *userdata, const std::string event);
+ static void setupPurpleSignals();
+
static void send(void *userdata, const std::string event);
static void invoke(void *userdata, const std::string event);
@@ -104,6 +127,11 @@ protected:
};
static void purpleCallback(void *userdata, const std::string event);
+ // libpurple debug
+ static void purpleDebugPrint(PurpleDebugLevel level, const char *category, const char *arg_s);
+ static gboolean purpleDebugIsEnabled(PurpleDebugLevel level, const char *category);
+
+
// libpurple core operations
static void purplePrefsInit(void);
static void purpleDebugInit(void);
diff --git a/src/uscxml/server/HTTPServer.cpp b/src/uscxml/server/HTTPServer.cpp
index 8799fc2..28b3ba4 100644
--- a/src/uscxml/server/HTTPServer.cpp
+++ b/src/uscxml/server/HTTPServer.cpp
@@ -8,6 +8,8 @@
#include "uscxml/server/HTTPServer.h"
#include "uscxml/Message.h"
#include "uscxml/Factory.h"
+
+#include <string>
#include <iostream>
#include <event2/dns.h>
#include <event2/event.h>
@@ -17,9 +19,6 @@
#include <event2/http_struct.h>
#include <event2/thread.h>
-#include <string>
-#include <iostream>
-
#include <glog/logging.h>
#include <boost/algorithm/string.hpp>
@@ -28,28 +27,38 @@
#include <arpa/inet.h>
#endif
+#if (defined EVENT_SSL_FOUND && defined OPENSSL_FOUND)
+#include <openssl/ssl.h>
+#include <openssl/bio.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <event2/bufferevent_ssl.h>
+#endif
+
#ifdef BUILD_AS_PLUGINS
#include <Pluma/Connector.hpp>
#endif
namespace uscxml {
-HTTPServer::HTTPServer(unsigned short port) {
+HTTPServer::HTTPServer(unsigned short port, SSLConfig* sslConf) {
_port = port;
_base = event_base_new();
_http = evhttp_new(_base);
_thread = NULL;
-
- evhttp_set_allowed_methods(_http,
- EVHTTP_REQ_GET |
- EVHTTP_REQ_POST |
- EVHTTP_REQ_HEAD |
- EVHTTP_REQ_PUT |
- EVHTTP_REQ_DELETE |
- EVHTTP_REQ_OPTIONS |
- EVHTTP_REQ_TRACE |
- EVHTTP_REQ_CONNECT |
- EVHTTP_REQ_PATCH); // allow all methods
+
+ unsigned int allowedMethods =
+ EVHTTP_REQ_GET |
+ EVHTTP_REQ_POST |
+ EVHTTP_REQ_HEAD |
+ EVHTTP_REQ_PUT |
+ EVHTTP_REQ_DELETE |
+ EVHTTP_REQ_OPTIONS |
+ EVHTTP_REQ_TRACE |
+ EVHTTP_REQ_CONNECT |
+ EVHTTP_REQ_PATCH;
+
+ evhttp_set_allowed_methods(_http, allowedMethods); // allow all methods
_handle = NULL;
while((_handle = evhttp_bind_socket_with_handle(_http, INADDR_ANY, _port)) == NULL) {
@@ -57,6 +66,46 @@ HTTPServer::HTTPServer(unsigned short port) {
}
determineAddress();
+#if (defined EVENT_SSL_FOUND && defined OPENSSL_FOUND)
+ if (!sslConf) {
+ _https = NULL;
+ _sslHandle = NULL;
+ _sslPort = 0;
+ } else {
+ _sslPort = sslConf->port;
+
+ // Initialize OpenSSL
+ SSL_library_init();
+ ERR_load_crypto_strings();
+ SSL_load_error_strings();
+ OpenSSL_add_all_algorithms();
+
+ _https = evhttp_new(_base);
+ evhttp_set_allowed_methods(_https, allowedMethods); // allow all methods
+
+ SSL_CTX* ctx = SSL_CTX_new (SSLv23_server_method ());
+ SSL_CTX_set_options(ctx,
+ SSL_OP_SINGLE_DH_USE |
+ SSL_OP_SINGLE_ECDH_USE |
+ SSL_OP_NO_SSLv2);
+
+ EC_KEY* ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
+ SSL_CTX_set_tmp_ecdh (ctx, ecdh);
+
+ SSL_CTX_use_certificate_chain_file(ctx, sslConf->publicKey.c_str());
+ SSL_CTX_use_PrivateKey_file(ctx, sslConf->privateKey.c_str(), SSL_FILETYPE_PEM);
+ SSL_CTX_check_private_key(ctx);
+
+ evhttp_set_bevcb(_https, sslBufferEventCallback, ctx);
+ evhttp_set_gencb(_https, sslGeneralBufferEventCallback, NULL);
+
+ _sslHandle = NULL;
+ while((_sslHandle = evhttp_bind_socket_with_handle(_https, INADDR_ANY, _sslPort)) == NULL) {
+ _sslPort++;
+ }
+ }
+#endif
+
// evhttp_set_timeout(_http, 5);
// generic callback
@@ -72,7 +121,7 @@ HTTPServer::~HTTPServer() {
HTTPServer* HTTPServer::_instance = NULL;
tthread::recursive_mutex HTTPServer::_instanceMutex;
-HTTPServer* HTTPServer::getInstance(int port) {
+HTTPServer* HTTPServer::getInstance(unsigned short port, SSLConfig* sslConf) {
// tthread::lock_guard<tthread::recursive_mutex> lock(_instanceMutex);
if (_instance == NULL) {
#ifdef _WIN32
@@ -84,12 +133,91 @@ HTTPServer* HTTPServer::getInstance(int port) {
#else
evthread_use_windows_threads();
#endif
- _instance = new HTTPServer(port);
+ _instance = new HTTPServer(port, sslConf);
_instance->start();
}
return _instance;
}
+#if (defined EVENT_SSL_FOUND && defined OPENSSL_FOUND)
+// see https://github.com/ppelleti/https-example/blob/master/https-server.c
+struct bufferevent* HTTPServer::sslBufferEventCallback(struct event_base *base, void *arg) {
+ struct bufferevent* r;
+ SSL_CTX *ctx = (SSL_CTX *) arg;
+ r = bufferevent_openssl_socket_new (base,
+ -1,
+ SSL_new (ctx),
+ BUFFEREVENT_SSL_ACCEPTING,
+ BEV_OPT_CLOSE_ON_FREE);
+ return r;
+}
+
+
+void HTTPServer::sslGeneralBufferEventCallback (struct evhttp_request *req, void *arg) {
+ struct evbuffer *evb = NULL;
+ const char *uri = evhttp_request_get_uri (req);
+ struct evhttp_uri *decoded = NULL;
+
+ /* We only handle POST requests. */
+ if (evhttp_request_get_command (req) != EVHTTP_REQ_POST)
+ { evhttp_send_reply (req, 200, "OK", NULL);
+ return;
+ }
+
+ printf ("Got a POST request for <%s>\n", uri);
+
+ /* Decode the URI */
+ decoded = evhttp_uri_parse (uri);
+ if (! decoded)
+ { printf ("It's not a good URI. Sending BADREQUEST\n");
+ evhttp_send_error (req, HTTP_BADREQUEST, 0);
+ return;
+ }
+
+ /* Decode the payload */
+ struct evkeyvalq kv;
+ memset (&kv, 0, sizeof (kv));
+ struct evbuffer *buf = evhttp_request_get_input_buffer (req);
+ evbuffer_add (buf, "", 1); /* NUL-terminate the buffer */
+ char *payload = (char *) evbuffer_pullup (buf, -1);
+ if (0 != evhttp_parse_query_str (payload, &kv))
+ { printf ("Malformed payload. Sending BADREQUEST\n");
+ evhttp_send_error (req, HTTP_BADREQUEST, 0);
+ return;
+ }
+
+ /* Determine peer */
+ char *peer_addr;
+ ev_uint16_t peer_port;
+ struct evhttp_connection *con = evhttp_request_get_connection (req);
+ evhttp_connection_get_peer (con, &peer_addr, &peer_port);
+
+ /* Extract passcode */
+ const char *passcode = evhttp_find_header (&kv, "passcode");
+ char response[256];
+ evutil_snprintf (response, sizeof (response),
+ "Hi %s! I %s your passcode.\n", peer_addr,
+ (0 == strcmp (passcode, "R23")
+ ? "liked"
+ : "didn't like"));
+ evhttp_clear_headers (&kv); /* to free memory held by kv */
+
+ /* This holds the content we're sending. */
+ evb = evbuffer_new ();
+
+ evhttp_add_header (evhttp_request_get_output_headers (req),
+ "Content-Type", "application/x-yaml");
+ evbuffer_add (evb, response, strlen (response));
+
+ evhttp_send_reply (req, 200, "OK", evb);
+
+ if (decoded)
+ evhttp_uri_free (decoded);
+ if (evb)
+ evbuffer_free (evb);
+}
+#endif
+
/**
* This callback is registered for all HTTP requests
*/
diff --git a/src/uscxml/server/HTTPServer.h b/src/uscxml/server/HTTPServer.h
index 3e0d91c..141ce7e 100644
--- a/src/uscxml/server/HTTPServer.h
+++ b/src/uscxml/server/HTTPServer.h
@@ -26,6 +26,14 @@ public:
}
};
+ class SSLConfig {
+ public:
+ SSLConfig() : port(8443) {}
+ std::string privateKey;
+ std::string publicKey;
+ unsigned short port;
+ };
+
class Reply {
public:
Reply(Request req) : status(200), type(req.data.compound["type"].atom), curlReq(req.curlReq) {}
@@ -41,7 +49,7 @@ public:
evhttp_request* httpReq;
};
- static HTTPServer* getInstance(int port = 8080);
+ static HTTPServer* getInstance(unsigned short port = 8080, SSLConfig* sslConf = NULL);
static std::string getBaseURL();
static void reply(const Reply& reply);
@@ -58,7 +66,7 @@ private:
};
};
- HTTPServer(unsigned short port);
+ HTTPServer(unsigned short port, SSLConfig* sslConf = NULL);
~HTTPServer();
void start();
@@ -90,6 +98,15 @@ private:
bool _isRunning;
friend class HTTPServlet;
+
+#if (defined EVENT_SSL_FOUND && defined OPENSSL_FOUND)
+ struct evhttp* _https;
+ struct evhttp_bound_socket* _sslHandle;
+ unsigned short _sslPort;
+
+ static struct bufferevent* sslBufferEventCallback(struct event_base *base, void *arg);
+ static void sslGeneralBufferEventCallback (struct evhttp_request *req, void *arg);
+#endif
};
class HTTPServlet {
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index de7fa70..51fe962 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -68,6 +68,11 @@ if (NOT WIN32)
add_test(test-stress ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-stress ${CMAKE_SOURCE_DIR}/test/samples/w3c)
set_target_properties(test-stress PROPERTIES FOLDER "Tests")
+ add_executable(test-instant-messaging src/test-instant-messaging.cpp)
+ target_link_libraries(test-instant-messaging uscxml)
+ add_test(test-instant-messaging ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-instant-messaging)
+ set_target_properties(test-instant-messaging PROPERTIES FOLDER "Tests")
+
endif()
add_executable(test-url src/test-url.cpp)
@@ -75,6 +80,12 @@ target_link_libraries(test-url uscxml)
add_test(test-url ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-url)
set_target_properties(test-url PROPERTIES FOLDER "Tests")
+
+add_executable(test-cmdline-parsing src/test-cmdline-parsing.cpp)
+target_link_libraries(test-cmdline-parsing uscxml)
+add_test(test-cmdline-parsing ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-cmdline-parsing)
+set_target_properties(test-cmdline-parsing PROPERTIES FOLDER "Tests")
+
# add_executable(test-initial-config src/test-initial-config.cpp)
# target_link_libraries(test-initial-config uscxml)
# add_test(test-url ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-initial-config ${CMAKE_SOURCE_DIR}/test/samples/uscxml/test-initial-config.scxml)
diff --git a/test/samples/uscxml/test-instant-messaging.scxml b/test/samples/uscxml/test-instant-messaging.scxml
index 6ca39d4..588b2b7 100644
--- a/test/samples/uscxml/test-instant-messaging.scxml
+++ b/test/samples/uscxml/test-instant-messaging.scxml
@@ -19,18 +19,25 @@
<param name="username" expr="'uscxml@localhost'" />
<param name="password" expr="'password'" />
<param name="protocol" expr="'prpl-jabber'" />
+ <finalize>
+ <script>print("-----------------\n"); dump(_event);</script>
+ </finalize>
</invoke>
<state id="dump">
<transition event="dump" target="dump">
<send event="dump" delay="1000ms" />
<script>//dump(_invokers['im']);</script>
- <send target="#_im" event="im.send">
- <param name="receiver" expr="'sradomski@localhost'" />
- <param name="data" expr="someBinaryData" />
- <content>Hey There!</content>
- </send>
</transition>
</state>
+
+ <transition event="im.buddy.status.changed" cond="_event.data.name === 'sradomski@localhost'">
+ <send target="#_im" event="im.send">
+ <param name="receiver" expr="'sradomski@localhost'" />
+ <param name="data" expr="someBinaryData" />
+ <content>Hey There!</content>
+ </send>
+ </transition>
+
</state>
</scxml> \ No newline at end of file
diff --git a/test/samples/uscxml/test-performance.scxml b/test/samples/uscxml/test-performance.scxml
index a102a18..4d2d4c4 100644
--- a/test/samples/uscxml/test-performance.scxml
+++ b/test/samples/uscxml/test-performance.scxml
@@ -1,6 +1,6 @@
<scxml datamodel="ecmascript">
<datamodel>
- <data id="iterations">1000</data>
+ <data id="iterations">10000</data>
</datamodel>
<state id="start">
<transition target="loop" />
diff --git a/test/samples/uscxml/test-startup-time.scxml b/test/samples/uscxml/test-startup-time.scxml
new file mode 100644
index 0000000..cc10f04
--- /dev/null
+++ b/test/samples/uscxml/test-startup-time.scxml
@@ -0,0 +1,4 @@
+<scxml datamodel="ecmascript">
+ <script>print("asdf");</script>
+ <state id="foo" final="true" />
+</scxml> \ No newline at end of file
diff --git a/test/src/test-arabica-events.cpp b/test/src/test-arabica-events.cpp
index 193b7ae..0cd45ee 100644
--- a/test/src/test-arabica-events.cpp
+++ b/test/src/test-arabica-events.cpp
@@ -1,3 +1,5 @@
+#include <iostream>
+
#include "uscxml/config.h"
#include "uscxml/Common.h"
#include <DOM/Document.hpp>
diff --git a/test/src/test-arabica-parsing.cpp b/test/src/test-arabica-parsing.cpp
index 24c58ae..24275fc 100644
--- a/test/src/test-arabica-parsing.cpp
+++ b/test/src/test-arabica-parsing.cpp
@@ -1,3 +1,5 @@
+#include <iostream>
+
#include "uscxml/config.h"
#include "uscxml/Common.h"
#include <DOM/Document.hpp>
diff --git a/test/src/test-arabica-xpath.cpp b/test/src/test-arabica-xpath.cpp
index 408cc2b..fe457f4 100644
--- a/test/src/test-arabica-xpath.cpp
+++ b/test/src/test-arabica-xpath.cpp
@@ -1,3 +1,5 @@
+#include <iostream>
+
#include <XPath/XPath.hpp>
#include <DOM/Simple/DOMImplementation.hpp>
#include <DOM/io/Stream.hpp>
diff --git a/test/src/test-cmdline-parsing.cpp b/test/src/test-cmdline-parsing.cpp
new file mode 100644
index 0000000..b0b909e
--- /dev/null
+++ b/test/src/test-cmdline-parsing.cpp
@@ -0,0 +1,109 @@
+#include "uscxml/config.h"
+#include "uscxml/Interpreter.h"
+#include <glog/logging.h>
+
+int main(int argc, char** argv) {
+ using namespace uscxml;
+
+ if (true) {
+ int testArgc = 11;
+ const char* testArgv[] = {
+ "test-cmdline-parsing",
+ "--verbose",
+ "--dot",
+ "--port=80",
+ "--ssl-port=8080",
+ "--certificate=/foo/bar.pem",
+ "--private-key=/foo/bar.priv",
+ "--public-key=/foo/bar.pub",
+ "--plugin-path=/foo/plugins",
+ "--loglevel=10",
+ "--disable-http",
+ 0
+ };
+ InterpreterOptions options = InterpreterOptions::fromCmdLine(testArgc, (char **)testArgv);
+ assert(options.verbose);
+ assert(options.useDot);
+ assert(options.httpPort == 80);
+ assert(options.httpsPort == 8080);
+ assert(boost::equals(options.certificate, "/foo/bar.pem"));
+ assert(boost::equals(options.privateKey, "/foo/bar.priv"));
+ assert(boost::equals(options.publicKey, "/foo/bar.pub"));
+ assert(boost::equals(options.pluginPath, "/foo/plugins"));
+ assert(options.logLevel == 10);
+ assert(!options.withHTTP);
+ assert(!options); // invalid as no SCXML document is given
+
+ optind = 0;
+ optreset = 1;
+ }
+
+ if (true) {
+ int testArgc = 3;
+ const char* testArgv[] = {
+ "test-cmdline-parsing",
+ "--verbose",
+ "/foo/bar.scxml",
+ 0
+ };
+ InterpreterOptions options = InterpreterOptions::fromCmdLine(testArgc, (char **)testArgv);
+ assert(options);
+ assert(options.verbose);
+ assert(options.interpreters.size() == 1);
+ assert(options.interpreters.find("/foo/bar.scxml") != options.interpreters.end());
+
+ optind = 0;
+ optreset = 1;
+ }
+
+ if (true) {
+ int testArgc = 7;
+ const char* testArgv[] = {
+ "test-cmdline-parsing",
+ "--port=80",
+ "/foo/bar1.scxml",
+ "--disable-http",
+ "/foo/bar2.scxml",
+ "/foo/bar3.scxml",
+ "--disable-http",
+ 0
+ };
+ InterpreterOptions options = InterpreterOptions::fromCmdLine(testArgc, (char **)testArgv);
+ assert(options);
+ assert(options.httpPort == 80);
+ assert(options.interpreters.size() == 3);
+ assert(options.interpreters.find("/foo/bar1.scxml") != options.interpreters.end());
+ assert(options.interpreters.find("/foo/bar2.scxml") != options.interpreters.end());
+ assert(options.interpreters.find("/foo/bar3.scxml") != options.interpreters.end());
+ assert(!options.interpreters["/foo/bar1.scxml"]->withHTTP);
+ assert(options.interpreters["/foo/bar2.scxml"]->withHTTP);
+ assert(!options.interpreters["/foo/bar3.scxml"]->withHTTP);
+
+ optind = 0;
+ optreset = 1;
+ }
+
+ if (true) {
+ int testArgc = 5;
+ const char* testArgv[] = {
+ "test-cmdline-parsing",
+ "--port=80",
+ "/foo/bar1.scxml",
+ "--vrml-path=/foo/bar.test",
+ "--tmp-path=/foo/bar.test",
+ 0
+ };
+ InterpreterOptions options = InterpreterOptions::fromCmdLine(testArgc, (char **)testArgv);
+ assert(options);
+ assert(options.httpPort == 80);
+ assert(options.interpreters.size() == 1);
+ assert(options.interpreters.find("/foo/bar1.scxml") != options.interpreters.end());
+ assert(options.interpreters["/foo/bar1.scxml"]->additionalParameters.find("vrml-path") != options.interpreters["/foo/bar1.scxml"]->additionalParameters.end());
+ assert(options.interpreters["/foo/bar1.scxml"]->additionalParameters.find("tmp-path") != options.interpreters["/foo/bar1.scxml"]->additionalParameters.end());
+
+ optind = 0;
+ optreset = 1;
+ }
+
+ return EXIT_SUCCESS;
+} \ No newline at end of file
diff --git a/test/src/test-instant-messaging.cpp b/test/src/test-instant-messaging.cpp
new file mode 100644
index 0000000..0bf2898
--- /dev/null
+++ b/test/src/test-instant-messaging.cpp
@@ -0,0 +1,298 @@
+/*
+ * pidgin
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ *
+ */
+
+#include "purple.h"
+
+#include <glib.h>
+
+#include <signal.h>
+#include <string.h>
+#ifndef _WIN32
+#include <unistd.h>
+#else
+#include "win32/win32dep.h"
+#endif
+
+#define CUSTOM_USER_DIRECTORY "/dev/null"
+#define CUSTOM_PLUGIN_PATH ""
+#define PLUGIN_SAVE_PREF "/purple/nullclient/plugins/saved"
+#define UI_ID "nullclient"
+
+/**
+ * The following eventloop functions are used in both pidgin and purple-text. If your
+ * application uses glib mainloop, you can safely use this verbatim.
+ */
+#define PURPLE_GLIB_READ_COND (G_IO_IN | G_IO_HUP | G_IO_ERR)
+#define PURPLE_GLIB_WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL)
+
+typedef struct _PurpleGLibIOClosure {
+ PurpleInputFunction function;
+ guint result;
+ gpointer data;
+} PurpleGLibIOClosure;
+
+static void purple_glib_io_destroy(gpointer data)
+{
+ g_free(data);
+}
+
+static gboolean purple_glib_io_invoke(GIOChannel *source, GIOCondition condition, gpointer data)
+{
+ PurpleGLibIOClosure *closure = (PurpleGLibIOClosure*)data;
+ int purple_cond = 0;
+
+ if (condition & PURPLE_GLIB_READ_COND)
+ purple_cond |= PURPLE_INPUT_READ;
+ if (condition & PURPLE_GLIB_WRITE_COND)
+ purple_cond |= PURPLE_INPUT_WRITE;
+
+ closure->function(closure->data, g_io_channel_unix_get_fd(source),
+ (PurpleInputCondition)purple_cond);
+
+ return TRUE;
+}
+
+static guint glib_input_add(gint fd, PurpleInputCondition condition, PurpleInputFunction function,
+ gpointer data)
+{
+ PurpleGLibIOClosure *closure = g_new0(PurpleGLibIOClosure, 1);
+ GIOChannel *channel;
+ int cond = 0;
+
+ closure->function = function;
+ closure->data = data;
+
+ if (condition & PURPLE_INPUT_READ)
+ cond |= PURPLE_GLIB_READ_COND;
+ if (condition & PURPLE_INPUT_WRITE)
+ cond |= PURPLE_GLIB_WRITE_COND;
+
+#if defined _WIN32 && !defined WINPIDGIN_USE_GLIB_IO_CHANNEL
+ channel = wpurple_g_io_channel_win32_new_socket(fd);
+#else
+ channel = g_io_channel_unix_new(fd);
+#endif
+ closure->result = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, (GIOCondition)cond,
+ purple_glib_io_invoke, closure, purple_glib_io_destroy);
+
+ g_io_channel_unref(channel);
+ return closure->result;
+}
+
+static PurpleEventLoopUiOps glib_eventloops =
+{
+ g_timeout_add,
+ g_source_remove,
+ glib_input_add,
+ g_source_remove,
+ NULL,
+ g_timeout_add_seconds,
+
+ /* padding */
+ NULL,
+ NULL,
+ NULL
+};
+/*** End of the eventloop functions. ***/
+
+/*** Conversation uiops ***/
+static void
+null_write_conv(PurpleConversation *conv, const char *who, const char *alias,
+ const char *message, PurpleMessageFlags flags, time_t mtime)
+{
+ const char *name;
+ if (alias && *alias)
+ name = alias;
+ else if (who && *who)
+ name = who;
+ else
+ name = NULL;
+
+ printf("(%s) %s %s: %s\n", purple_conversation_get_name(conv),
+ purple_utf8_strftime("(%H:%M:%S)", localtime(&mtime)),
+ name, message);
+}
+
+static PurpleConversationUiOps null_conv_uiops =
+{
+ NULL, /* create_conversation */
+ NULL, /* destroy_conversation */
+ NULL, /* write_chat */
+ NULL, /* write_im */
+ null_write_conv, /* write_conv */
+ NULL, /* chat_add_users */
+ NULL, /* chat_rename_user */
+ NULL, /* chat_remove_users */
+ NULL, /* chat_update_user */
+ NULL, /* present */
+ NULL, /* has_focus */
+ NULL, /* custom_smiley_add */
+ NULL, /* custom_smiley_write */
+ NULL, /* custom_smiley_close */
+ NULL, /* send_confirm */
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+static void
+null_ui_init(void)
+{
+ /**
+ * This should initialize the UI components for all the modules. Here we
+ * just initialize the UI for conversations.
+ */
+ purple_conversations_set_ui_ops(&null_conv_uiops);
+}
+
+static PurpleCoreUiOps null_core_uiops =
+{
+ NULL,
+ NULL,
+ null_ui_init,
+ NULL,
+
+ /* padding */
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+static void
+init_libpurple(void)
+{
+ /* Set a custom user directory (optional) */
+ purple_util_set_user_dir(CUSTOM_USER_DIRECTORY);
+
+ /* We do not want any debugging for now to keep the noise to a minimum. */
+ purple_debug_set_enabled(FALSE);
+
+ /* Set the core-uiops, which is used to
+ * - initialize the ui specific preferences.
+ * - initialize the debug ui.
+ * - initialize the ui components for all the modules.
+ * - uninitialize the ui components for all the modules when the core terminates.
+ */
+ purple_core_set_ui_ops(&null_core_uiops);
+
+ /* Set the uiops for the eventloop. If your client is glib-based, you can safely
+ * copy this verbatim. */
+ purple_eventloop_set_ui_ops(&glib_eventloops);
+
+ /* Set path to search for plugins. The core (libpurple) takes care of loading the
+ * core-plugins, which includes the protocol-plugins. So it is not essential to add
+ * any path here, but it might be desired, especially for ui-specific plugins. */
+ purple_plugins_add_search_path(CUSTOM_PLUGIN_PATH);
+
+ /* Now that all the essential stuff has been set, let's try to init the core. It's
+ * necessary to provide a non-NULL name for the current ui to the core. This name
+ * is used by stuff that depends on this ui, for example the ui-specific plugins. */
+ if (!purple_core_init(UI_ID)) {
+ /* Initializing the core failed. Terminate. */
+ fprintf(stderr,
+ "libpurple initialization failed. Dumping core.\n"
+ "Please report this!\n");
+ abort();
+ }
+
+ /* Load the preferences. */
+ purple_prefs_load();
+
+ /* Load the desired plugins. The client should save the list of loaded plugins in
+ * the preferences using purple_plugins_save_loaded(PLUGIN_SAVE_PREF) */
+ purple_plugins_load_saved(PLUGIN_SAVE_PREF);
+}
+
+static void
+signed_on(PurpleConnection *gc, gpointer null)
+{
+ PurpleAccount *account = purple_connection_get_account(gc);
+ printf("Account connected: %s %s\n", purple_account_get_username(account), purple_account_get_protocol_id(account));
+}
+
+static void
+buddy_signed_on(PurpleBuddy *buddy) {
+ PurpleConnection *gc = purple_account_get_connection(purple_buddy_get_account(buddy));
+ PurplePlugin* prpl = purple_connection_get_prpl(gc);
+ PurplePluginProtocolInfo* prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+
+ if (prpl_info->send_file && (prpl_info->can_receive_file && prpl_info->can_receive_file(gc, "sradomski@localhost"))) {
+ prpl_info->send_file(gc, "sradomski@localhost", "/Users/sradomski/Documents/W3C Standards.pdf");
+ }
+
+}
+
+static void
+connect_to_signals_for_demonstration_purposes_only(void)
+{
+ static int handle;
+ purple_signal_connect(purple_connections_get_handle(), "signed-on", &handle,
+ PURPLE_CALLBACK(signed_on), NULL);
+ purple_signal_connect(purple_blist_get_handle(), "buddy-signed-on", &handle,
+ PURPLE_CALLBACK(buddy_signed_on), NULL);
+}
+
+int main(int argc, char *argv[])
+{
+ GList *iter;
+ GMainLoop *loop = g_main_loop_new(NULL, FALSE);
+ PurpleAccount *account;
+ PurpleSavedStatus *status;
+
+#ifndef _WIN32
+ /* libpurple's built-in DNS resolution forks processes to perform
+ * blocking lookups without blocking the main process. It does not
+ * handle SIGCHLD itself, so if the UI does not you quickly get an army
+ * of zombie subprocesses marching around.
+ */
+ signal(SIGCHLD, SIG_IGN);
+#endif
+
+ init_libpurple();
+
+ printf("libpurple initialized.\n");
+
+ iter = purple_plugins_get_protocols();
+
+ /* Create the account */
+ account = purple_account_new("uscxml@localhost", "prpl-jabber");
+
+ /* Get the password for the account */
+ purple_account_set_password(account, "password", NULL, NULL);
+
+ /* It's necessary to enable the account first. */
+ purple_account_set_enabled(account, UI_ID, TRUE);
+
+ /* Now, to connect the account(s), create a status and activate it. */
+ status = purple_savedstatus_new(NULL, PURPLE_STATUS_AVAILABLE);
+ purple_savedstatus_activate(status);
+
+ connect_to_signals_for_demonstration_purposes_only();
+
+ g_main_loop_run(loop);
+
+ return 0;
+}
+