CellMLToSharedLibraryConverter.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2010
00004 
00005 University of Oxford means the Chancellor, Masters and Scholars of the
00006 University of Oxford, having an administrative office at Wellington
00007 Square, Oxford OX1 2JD, UK.
00008 
00009 This file is part of Chaste.
00010 
00011 Chaste is free software: you can redistribute it and/or modify it
00012 under the terms of the GNU Lesser General Public License as published
00013 by the Free Software Foundation, either version 2.1 of the License, or
00014 (at your option) any later version.
00015 
00016 Chaste is distributed in the hope that it will be useful, but WITHOUT
00017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00019 License for more details. The offer of Chaste under the terms of the
00020 License is subject to the License being interpreted in accordance with
00021 English Law and subject to any action against the University of Oxford
00022 being under the jurisdiction of the English Courts.
00023 
00024 You should have received a copy of the GNU Lesser General Public License
00025 along with Chaste. If not, see <http://www.gnu.org/licenses/>.
00026 
00027 */
00028 
00029 #include "CellMLToSharedLibraryConverter.hpp"
00030 
00031 #include <sstream>
00032 #include <unistd.h> // For getpid()
00033 #include <sys/stat.h> // For mkdir()
00034 #include <ctime>
00035 
00036 #include "Exception.hpp"
00037 #include "ChasteBuildRoot.hpp"
00038 #include "PetscTools.hpp"
00039 #include "DynamicModelLoaderRegistry.hpp"
00040 #include "GetCurrentWorkingDirectory.hpp"
00041 
00042 CellMLToSharedLibraryConverter::CellMLToSharedLibraryConverter(std::string component)
00043     : mComponentName(component)
00044 {
00045 }
00046 
00047 DynamicCellModelLoader* CellMLToSharedLibraryConverter::Convert(const FileFinder& rFilePath,
00048                                                                 bool isCollective)
00049 {
00050     DynamicCellModelLoader* p_loader;
00051     std::string absolute_path = rFilePath.GetAbsolutePath();
00052     // Check the file exists
00053     if (!rFilePath.Exists())
00054     {
00055         EXCEPTION("Dynamically loadable cell model '" + absolute_path + "' does not exist.");
00056     }
00057     // Find out whether rFilePath is a .cellml or .so
00058     size_t dot_position = absolute_path.find_last_of(".");
00059     if (dot_position == std::string::npos)
00060     {
00061         EXCEPTION("File does not have an extension: " + absolute_path);
00062     }
00063     std::string extension = absolute_path.substr(dot_position+1);
00064     if (extension == "cellml")
00065     {
00066         // Split the path into folder and leaf
00067         size_t slash_position = absolute_path.find_last_of("/\\");
00068         assert(slash_position != std::string::npos);
00069         std::string folder = absolute_path.substr(0, slash_position+1); // Include trailing slash
00070         std::string leaf = absolute_path.substr(slash_position+1, dot_position-slash_position); // Include dot
00071         std::string so_path = folder + "lib" + leaf + "so";
00072         // Does the .so file already exist (and was it modified after the .cellml?)
00073         FileFinder so_file(so_path, RelativeTo::Absolute);
00074         if (!so_file.Exists() || rFilePath.IsNewerThan(so_file))
00075         {
00076             if (!isCollective)
00077             {
00078                 EXCEPTION("Unable to convert .cellml to .so unless called collectively, due to possible race conditions.");
00079             }
00080             ConvertCellmlToSo(absolute_path, folder, leaf);
00081         }
00082         // Load the .so
00083         p_loader = DynamicModelLoaderRegistry::Instance()->GetLoader(so_file);
00084     }
00085     else if (extension == "so")
00086     {
00087         // Just load the .so
00088         p_loader = DynamicModelLoaderRegistry::Instance()->GetLoader(rFilePath);
00089     }
00090     else
00091     {
00092         EXCEPTION("Unsupported extension '." + extension + "' of file '" + absolute_path + "'; must be .so or .cellml");
00093     }
00094 
00095     return p_loader;
00096 }
00097 
00098 void CellMLToSharedLibraryConverter::ConvertCellmlToSo(const std::string& rCellmlFullPath,
00099                                                        const std::string& rCellmlFolder,
00100                                                        const std::string& rModelLeafName)
00101 {
00102     std::string tmp_folder, build_folder;
00103     std::string old_cwd = GetCurrentWorkingDirectory();
00104     try
00105     {
00106         // Need to create a .so file from the CellML...
00107         if (PetscTools::AmMaster())
00108         {
00109             // Create a temporary folder within heart/dynamic
00110             std::stringstream folder_name;
00111             folder_name << "dynamic/tmp_" << getpid() << "_" << time(NULL);
00112             tmp_folder = std::string(ChasteBuildRootDir()) + mComponentName + "/" + folder_name.str();
00113             build_folder = std::string(ChasteBuildRootDir()) + mComponentName + "/build/" + ChasteBuildDirName() + "/" + folder_name.str();
00114             int ret = mkdir(tmp_folder.c_str(), 0700);
00115             if (ret != 0)
00116             { // Some optimised builds see ret as unused if this line is just assert(ret==0);
00117                 NEVER_REACHED;
00118             }
00119             // Copy the .cellml file (and any relevant others) into the temporary folder
00120             size_t dot_pos = rCellmlFullPath.rfind('.');
00121             std::string cellml_base = rCellmlFullPath.substr(0, dot_pos);
00122             EXPECT0(system, "cp " + cellml_base + "* " + tmp_folder);
00123             // If there's a config file, copy that too
00124             std::string config_path = rCellmlFullPath.substr(0, rCellmlFullPath.length() - 7) + "-conf.xml";
00125             if (FileFinder(config_path, RelativeTo::Absolute).Exists())
00126             {
00127                 EXPECT0(system, "cp " + config_path + " " + tmp_folder);
00128             }
00129             // Change to Chaste source folder
00130             EXPECT0(chdir, ChasteBuildRootDir());
00131             // Run scons to generate C++ code and compile it to a .so
00132             EXPECT0(system, "scons dyn_libs_only=1 build=" + ChasteBuildType() + " " + tmp_folder);
00133             EXCEPT_IF_NOT(FileFinder(tmp_folder + "/lib" + rModelLeafName + "so", RelativeTo::Absolute).Exists());
00134             // CD back
00135             EXPECT0(chdir, old_cwd);
00136             // Copy the .so to the same folder as the original .cellml file
00137             EXPECT0(system, "cp " + tmp_folder + "/lib" + rModelLeafName + "so " + rCellmlFolder);
00138             // Delete the temporary folders
00139             EXPECT0(system, "rm -r " + build_folder);
00140             EXPECT0(system, "rm -r " + tmp_folder);
00141         }
00142     }
00143     catch (Exception& e)
00144     {
00145         PetscTools::ReplicateException(true);
00146         // Delete the temporary folders
00147         EXPECT0(system, "rm -rf " + build_folder); // -f because folder might not exist
00148         EXPECT0(system, "rm -r " + tmp_folder);
00149         EXPECT0(chdir, old_cwd);
00150         EXCEPTION("Conversion of CellML to Chaste shared object failed. Error was: " + e.GetMessage());
00151     }
00152     // This also has the effect of a barrier, ensuring all processes wait for the
00153     // shared library to be created.
00154     PetscTools::ReplicateException(false);
00155 }

Generated on Mon Nov 1 12:35:16 2010 for Chaste by  doxygen 1.5.5