Если ваша разделяемая библиотека содержит типы данных или функции языка, не поддерживавшие интерфейсом MATLAB® к библиотекам C++, вы можете смочь включать эту функциональность путем создания заголовочного файла обертки. Эта тема обеспечивает примеры для некоторых ограничений. Для получения дополнительной информации смотрите Ограничения к Поддержке C/C++.
Запускать примеры обходного решения на Windows®:
Скопируйте операторы заголовочного файла C++ в .hpp
файлы.
Скопируйте исходный код в .cpp
файлы и сборка, с помощью инструкций в Примере Сборки Совместно использовали Файлы Библиотеки на Windows.
Выполните код MATLAB, чтобы создать интерфейс.
При необходимости отредактируйте файл определения библиотеки.
Выполните код MATLAB, чтобы протестировать функциональность.
std
Пространство именИнтерфейс MATLAB к библиотеке C++ не включает функции, которые используют объекты, заданные в std
пространство имен. Например, функции в этом Student.hpp
передача заголовочного файла std::stack
объекты. Если вы создаете интерфейс MATLAB, readStudents
функций и
getStudents
не включены.
#ifndef STUDENT_HEADER #define STUDENT_HEADER #include <stack> #ifdef _WIN32 #ifdef EXPORT #define DLL_EXPORT __declspec(dllexport) #else #define DLL_EXPORT __declspec(dllimport) #endif #else #define DLL_EXPORT __attribute__((visibility ("default"))) #endif class DLL_EXPORT Student { int rollNumber; public: Student(); Student(int rollNo); int getRollNumber(); }; DLL_EXPORT void readStudents(const std::stack<Student>& students); DLL_EXPORT std::stack<Student> getStudents(int size); #endif
Чтобы запустить этот пример на Windows, создайте Student.lib
и Student.dll
файлы от этого Student.cpp
исходный файл, с помощью Примера Сборки Совместно использовал Файлы Библиотеки на Windows.
#define EXPORT #include "Student.hpp" Student::Student() : rollNumber(0) {} Student::Student(int rollNo) : rollNumber(rollNo) {} int Student::getRollNumber() { return rollNumber; } DLL_EXPORT void readStudents(const std::stack<Student>& students) { } DLL_EXPORT std::stack<Student> getStudents(int size) { std::stack<Student> students; for (int i = 0; i < size; i++) { students.push(Student(i+1)); } return students; }
Создайте Student.hpp
заголовочный файл и помещенный это с Student.dll
совместно использованный файл библиотеки в папке, идентифицированной как rtpath
.
Создайте класс CStack
представлять std::stack
объект. Поместите это определение в заголовочный файл CStack.hpp
.
//Wrapper header to access/pass std::stack objects from MATLAB #ifndef stack_header #define stack_header #include <stack> #include <stdexcept> template<typename T> class CStack { std::stack<T> data; public: CStack() {} // This parameterized constructor is required for the wrapper functions // and is not included in the MATLAB interface CStack(const std::stack<T>& d):data(d) {} // Function to access the topmost element in stack T* get() { if (data.empty()) throw std::runtime_error("Retrieving element from Empty Stack"); return &data.top(); } // Function to remove elements from stack void remove() { if (data.empty()) throw std::runtime_error("Stack is empty"); data.pop(); } // Function to add elements to stack void add(const T* element) { data.push(*element); } // This method is required for the wrapper functions, and // is not included in the MATLAB interface const std::stack<T>& getData() const{ return data; } }; #endif
Задайте функциональный readStudentsWrapper
вызывать readStudents
функция с помощью CStack
класс и getStudentsWrapper
вызывать getStudents
функция. Включайте эти функции в заголовочный файл обертки под названием StudentWrapper.hpp
.
//Header to call readStudents and getStudents functions from MATLAB #include "Student.hpp" #include "CStack.hpp" //wrapper function to access the function that accepts std::stack input void readStudentsWrapper(const CStack<Student>& students) { readStudents(students.getData()); } //wrapper function to access the function that returns the std::stack CStack<Student> getStudentsWrapper(int size) { auto students = getStudents(size); CStack<Student> cstackStudents(students); return cstackStudents; }
Сгенерируйте определение библиотеки в пакете под названием stack
.
clibgen.generateLibraryDefinition(["Student.hpp","StudentWrapper.hpp"],"PackageName","stack",... "Libraries","Student.lib","TreatObjectPointerAsScalar",true,"Verbose",true);
Warning: File 'manifest.json' not found. Warning: Some C++ language constructs in the header file are not supported and not imported. Did not add 'readStudents' at Student.hpp:24. Type 'stack' is from std namespace or system header and is not supported. Did not add 'getStudents' at Student.hpp:26. Type 'stack' is from std namespace or system header and is not supported. Did not add constructor to class 'CStack<Student>' at CStack.hpp:16. Type 'stack' is from std namespace or system header and is not supported. Did not add member 'getData' to class 'CStack<Student>' at CStack.hpp:39. Type 'stack' is from std namespace or system header and is not supported. Using MinGW64 Compiler (C++) compiler. Generated definition file definestack.mlx and data file 'stackData.xml' contain definitions for 13 constructs supported by MATLAB. Build using build(definestack).
Проигнорируйте Did not add
сообщения. В MATLAB вы вызываете функции readStudentsWrapper
и getStudentsWrapper
вместо readStudents
и getStudents
. Конструктор, чтобы классифицировать CStack
и член getData
используются внутренне и не вызываемые от интерфейса.
Создайте интерфейс.
build(definestack)
addpath('stack')
Добавьте разделяемый путь к библиотеке к системе (время выполнения) путь. Если файл расположен на rtPath
, затем тип:
syspath = getenv('PATH'); rtPath = 'myrtpathname'; setenv('PATH',[rtPath ';' syspath]);
Вызовите readStudentsWrapper
.
studentsStack = clib.stack.CStack_Student_; studentsStack.add(clib.stack.Student(1)) studentsStack.add(clib.stack.Student(2)) studentsStack.add(clib.stack.Student(3)) clib.stack.readStudentsWrapper(studentsStack)
Вызовите getStudentsWrapper
.
clear studentsStack; studentsStack = clib.stack.getStudentsWrapper(3); student = studentsStack.get; % returns topmost element from studentStack studentsStack.remove % removes topmost element of stack
Интерфейс MATLAB к библиотеке C++ не поддерживает неинстанцированные шаблонные классы. Например, класс Pairs
в этом Templates.hpp
заголовочный файл не инстанцируют.
// Header for Template class #ifndef templates_Header #define templates_Header template <class T> class Pairs { public: T val1; T val2; Pairs() : val1(0), val2(0) {} Pairs(T first, T second) : val1(first), val2(second) {} T getVal1() { return val1; } T getVal2() { return val2; } }; #endif
Включать Pairs
класс, создайте этот заголовочный файл обертки TemplatesWrapper.hpp
. Примите тот Pairs
поддержки int
и double
типы данных.
//Wrapper to instantiate template class Pairs #include "Templates.hpp" /* Data types that will be used for Pairs class. */ template class Pairs<int>; template class Pairs<double>;
Сгенерируйте определение библиотеки.
clibgen.generateLibraryDefinition(["TemplatesWrapper.hpp","Templates.hpp"],"PackageName","Templates","Verbose",true)
Generated definition file defineTemplates.mlx and data file 'TemplatesData.xml' contain definitions for 16 constructs supported by MATLAB. Build using build(defineTemplates).
Создайте интерфейс.
build(defineTemplates)
addpath('Templates')
Создайте Pairs
объекты и вызов getVal1
и getVal2
функции.
Pairs1 = clib.Templates.Pairs_int_(2,3); Val1 = Pairs1.getVal1; Pairs2 = clib.Templates.Pairs_double_(4.5,10.9); Val2 = Pairs2.getVal2; Pairs3 = clib.Templates.Pairs_int_(4.3,10.9); Val2 = Pairs3.getVal2;
Интерфейс MATLAB к библиотеке C++ не включает функции с void *
аргументы или возвращают типы. Например, если вы создаете интерфейс MATLAB к этому ContentHidden.hpp
заголовочный файл, getObjWithContentHidden
и sizeOfObjWithContentHidden
функции не включены.
//Header file with void* as argument/return type for function #ifndef CONTENT_HIDDEN #define CONTENT_HIDDEN #include <vector> #ifdef _WIN32 #ifdef EXPORT #define DLL_EXPORT __declspec(dllexport) #else #define DLL_EXPORT __declspec(dllimport) #endif #else #define DLL_EXPORT __attribute__((visibility ("default"))) #endif DLL_EXPORT void* getObjWithContentHidden(); //function with return type as void pointer gets dropped in MATLAB C++ Interface DLL_EXPORT unsigned int sizeOfObjWithContentHidden(void* pobj); //function with argument as void pointer gets dropped in MATLAB C++ Interface #endif
Чтобы запустить этот пример на Windows, создайте ContentHidden.lib
и ContentHidden.dll
файлы от этого ContentHidden.cpp
исходный файл, с помощью Примера Сборки Совместно использовал Файлы Библиотеки на Windows.
#define EXPORT #include "ContentHidden.hpp" DLL_EXPORT void* getObjWithContentHidden() { std::vector<int> *vecData = new std::vector<int>({1,2,3,4}); return vecData; } DLL_EXPORT unsigned int sizeOfObjWithContentHidden(void* pobj) { return (static_cast<std::vector<int> *> (pobj))->size(); }
Создайте ContentHidden.hpp
заголовочный файл и помещенный это с ContentHidden.dll
совместно использованный файл библиотеки в папке, идентифицированной как rtpath
.
Задайте функциональный getObjWrapper
вызывать getObjWithContentHidden
функция и sizeOfObjWrapper
вызывать sizeOfObjWithContentHidden
функция. Включайте эти функции в заголовочный файл обертки под названием VoidPointerWrapper.hpp
.
//Wrapper to access function with void* as argument/return type #pragma once #include "ContentHidden.hpp" class VoidType {}; //wrapper class to convert void* to VoidType* VoidType* getObjWrapper() { return static_cast<VoidType*> (getObjWithContentHidden()); } unsigned int sizeOfObjWrapper(VoidType* pobj) { return sizeOfObjWithContentHidden(pobj); }
Сгенерируйте определение библиотеки в пакете под названием VoidPointer
.
clibgen.generateLibraryDefinition(["ContentHidden.hpp","VoidPointerWrapper.hpp"],"PackageName","VoidPointer",... "Libraries","ContentHidden.lib","TreatObjectPointerAsScalar",true,"Verbose",true)
Warning: Some C++ language constructs in the header file are not supported and not imported. Did not add 'getObjWithContentHidden' at ContentHidden.hpp:17. 'void *' is not a supported type. Did not add 'sizeOfObjWithContentHidden' at ContentHidden.hpp:19. 'void *' is not a supported type. Using MinGW64 Compiler (C++) compiler. Generated definition file defineVoidPointer.mlx and data file 'VoidPointerData.xml' contain definitions for 5 constructs supported by MATLAB. Build using build(defineVoidPointer).
Проигнорируйте Did not add
сообщения. В MATLAB вы вызываете функции getObjWrapper
и sizeOfObjWrapper
вместо getObj
и sizeOfObj
..
Создайте интерфейс.
build(defineVoidPointer)
addpath('VoidPointer')
Отобразите содержимое интерфейса.
summary(defineVoidPointer)
MATLAB Interface to VoidPointer Library Class clib.VoidPointer.VoidType Constructors: clib.VoidPointer.VoidType() clib.VoidPointer.VoidType(clib.VoidPointer.VoidType) No Methods defined No Properties defined Functions clib.VoidPointer.VoidType clib.VoidPointer.getObjWrapper() uint32 clib.VoidPointer.sizeOfObjWrapper(clib.VoidPointer.VoidType)
Добавьте разделяемый путь к библиотеке к системе (время выполнения) путь. Если файл расположен на rtPath
, затем тип:
syspath = getenv('PATH'); rtPath = 'myrtpathname'; setenv('PATH',[rtPath ';' syspath]);
Вызовите функции.
voidObj = clib.VoidPointer.getObjWrapper objSize = clib.VoidPointer.sizeOfObjWrapper(voidObj)
voidObj = VoidType with no properties. objSize = uint32 4
Интерфейс MATLAB к библиотеке C++ не делает входных параметров указателя функции поддержки. Например, этот CreateTrackbar.hpp
заголовочный файл задает CvTrackbarCallback
как указатель функции. Если вы создаете интерфейс MATLAB, cvCreateTrackbar
функция не включена потому что аргумент on_change
указатель функции CvTrackbarCallback
ввод.
#ifndef trackbar_header #define trackbar_header #ifdef _WIN32 #ifdef EXPORT #define DLL_EXPORT __declspec(dllexport) #else #define DLL_EXPORT __declspec(dllimport) #endif #else #define DLL_EXPORT __attribute__((visibility ("default"))) #endif #include <cstddef> typedef void( *CvTrackbarCallback) (int pos, void *userdata); //Function "cvCreateTrackbar" gets dropped in MATLAB C++ Interface due to Function Pointer input argument DLL_EXPORT int cvCreateTrackbar(const char *trackbar_name, const char *window_name, int *value, int count, CvTrackbarCallback on_change); DLL_EXPORT void MatchingMethod( int, void* ); #endif
Чтобы запустить этот пример на Windows, создайте CreateTrackbar.lib
и CreateTrackbar.dll
файлы от этого CreateTrackbar.cpp
исходный файл, с помощью Примера Сборки Совместно использовал Файлы Библиотеки на Windows.
#define EXPORT #include "CreateTrackbar.hpp" #include <iostream> DLL_EXPORT int cvCreateTrackbar(const char *trackbar_name, const char *window_name, int *value, int count, CvTrackbarCallback on_change = NULL){ return count; } DLL_EXPORT void MatchingMethod(int, void*){ std::cout << "Invoked Function : MatchingMethod" << std::endl; }
Создайте CreateTrackbar.hpp
заголовочный файл и помещенный это с CreateTrackbar.dll
совместно использованный файл библиотеки в папке, идентифицированной как rtpath
.
Включать cvCreateTrackbar
, создайте этот заголовочный файл обертки WrapperTrackbar.hpp
который задает wrapperTrackbar
получить доступ к функции, которая принимает вход указателя функции.
// Wrapper Header to access function pointer CvTrackbarCallback #include "CreateTrackbar.hpp" using CvTrackbarCallback = void (*) (int , void *); class CvTrackbarCallbackWrapper { public: CvTrackbarCallback const on_change; CvTrackbarCallbackWrapper(CvTrackbarCallback fptr) : on_change(fptr) {} }; template<CvTrackbarCallback fptr> class CvTrackbarCallbackWrapperTempl : public CvTrackbarCallbackWrapper { public: CvTrackbarCallbackWrapperTempl() : CvTrackbarCallbackWrapper(fptr){} }; template class CvTrackbarCallbackWrapperTempl<MatchingMethod>; // Wrapper function to access the function that accepts function pointer input int wrapperTrackbar(const char *trackbar_name, const char *window_name, int *value, int count, CvTrackbarCallbackWrapper const &callbackWrapper) { return cvCreateTrackbar(trackbar_name, window_name, value, count, callbackWrapper.on_change); }
Сгенерируйте определение библиотеки.
clibgen.generateLibraryDefinition(["CreateTrackbar.hpp","WrapperTrackbar.hpp"],"PackageName","Trackbar",... "Libraries","CreateTrackbar.lib","TreatObjectPointerAsScalar",true,"Verbose",true)
Warning: Some C++ language constructs in the header file are not supported and not imported. Did not add member 'on_change' to class 'CvTrackbarCallbackWrapper' at WrapperTrackbar.hpp:8. 'CvTrackbarCallback' is an alias of type '*'. 'CvTrackbarCallback const' is not a supported type. Did not add constructor to class 'CvTrackbarCallbackWrapper' at WrapperTrackbar.hpp:9. 'CvTrackbarCallback' is an alias of type '*'. '*' is not a supported type. Did not add 'MatchingMethod' at CreateTrackbar.hpp:21. 'void *' is not a supported type. Did not add 'cvCreateTrackbar' at CreateTrackbar.hpp:19. 'CvTrackbarCallback' is an alias of type '*'. '*' is not a supported type. Using MinGW64 Compiler (C++) compiler. Generated definition file defineTrackbar.mlx and data file 'TrackbarData.xml' contain definitions for 7 constructs supported by MATLAB. 1 construct(s) require(s) additional definition. To include these construct(s) in the interface, edit the definitions in defineTrackbar.mlx. Build using build(defineTrackbar).
Чтобы включать недостающие определения, отредактируйте defineTrackbar.mlx
и задайте аргументы имени к wrapperTrackbar
как отключенные пустым указателем строки. Обновленный код для trackbar_name
:
defineArgument(wrapperTrackbarDefinition, "trackbar_name", "string", "input", "nullTerminated");
Обновленный код для window_name
:
defineArgument(wrapperTrackbarDefinition, "window_name", "string", "input", "nullTerminated");
Задайте value
как int32
скаляр. Обновленный код:
defineArgument(wrapperTrackbarDefinition, "value", 'int32', "input", 1);
Сохраните файл и создайте интерфейс.
build(defineTrackbar)
addpath('Trackbar')
Добавьте разделяемый путь к библиотеке к системе (время выполнения) путь. Если файл расположен на rtPath
, затем тип:
syspath = getenv('PATH'); rtPath = 'myrtpathname'; setenv('PATH',[rtPath ';' syspath]);
Вызовите функции.
% Create a function pointer object. matchingMethodObj = clib.Trackbar.CvTrackbarCallbackWrapperTempl_MatchingMethod_; trackbar_label = "Method: \n 0: SQDIFF \n 1: SQDIFF NORMED \n 2: TM CCORR \n 3: TM CCORR NORMED \n 4: TM COEFF \n 5: TM COEFF NORMED"; image_window = "Source Image"; match_method = 0; max_Trackbar = 5; % Use the wrapper function to call cvCreateTrackbar with a function pointer input val = clib.Trackbar.wrapperTrackbar(trackbar_label,image_window,match_method,max_Trackbar,matchingMethodObj)
Интерфейс MATLAB к библиотеке C++ не поддерживает директивы препроцессору (макросы). Например, этот Area.hpp
заголовочный файл задает макро-PI
. Если вы создаете интерфейс MATLAB, PI
не включен.
//Header with Macro preprocessor directive #ifndef area_header #define area_header #ifdef _WIN32 #ifdef EXPORT #define DLL_EXPORT __declspec(dllexport) #else #define DLL_EXPORT __declspec(dllimport) #endif #else #define DLL_EXPORT __attribute__((visibility ("default"))) #endif #define PI 3.1415 DLL_EXPORT double getArea(int radius, double piVal); #endif
Чтобы запустить этот пример на Windows, создайте Area.lib
и Area.dll
файлы от этого Area.cpp
исходный файл, с помощью Примера Сборки Совместно использовал Файлы Библиотеки на Windows.
#define EXPORT #include "Area.hpp" DLL_EXPORT double getArea(int radius, double piVal) { return piVal*radius*radius; }
Создайте Area.hpp
заголовочный файл и помещенный это с Area.dll
совместно использованный файл библиотеки в папке, идентифицированной как rtpath
.
Включать PI
, создайте этот заголовочный файл обертки WrapperPI.hpp
который задает функциональный getPI
получить значение директивы препроцессору.
//Wrapper to access the preprocessor directive value #include "Area.hpp" double getPI(){ //Wrapper function retrieves the value of PI return PI; }
Сгенерируйте определение библиотеки.
clibgen.generateLibraryDefinition(["Area.hpp","WrapperPI.hpp"],"PackageName","Area",... "Libraries","Area.lib","TreatObjectPointerAsScalar",true,"Verbose",true)
Создайте интерфейс.
build(defineArea)
addpath('Area')
Добавьте разделяемый путь к библиотеке к системе (время выполнения) путь. Если файл расположен на rtPath
, затем тип:
syspath = getenv('PATH'); rtPath = 'myrtpathname'; setenv('PATH',[rtPath ';' syspath]);
Вызовите getArea
.
pi = clib.Area.getPI; area = clib.Area.getArea(2,pi)
area = 12.5660
Интерфейс MATLAB к библиотеке C++ не включает функции с аргументами std::string
для типа элемента вектора. Например, readStringVector
и getStringVector
функции в этом StringVector.hpp
заголовочный файл не включен, когда вы создаете интерфейс MATLAB.
//Header file which accepts and return the vector of std::string #ifndef stringVec_header #define stringVec_header #include <vector> #include <string> #ifdef _WIN32 #ifdef EXPORT #define DLL_EXPORT __declspec(dllexport) #else #define DLL_EXPORT __declspec(dllimport) #endif #else #define DLL_EXPORT __attribute__((visibility ("default"))) #endif DLL_EXPORT void readStringVector(const std::vector<std::string>& stringVector); //readStringVector function gets dropped as vector of std::string input is not supported in MATLAB C++ interface. DLL_EXPORT std::vector<std::string> getStringVector(int size); //getStringVector function gets dropped as return type of vector of std::string is not supported for MATLAB C++ Interface #endif
Чтобы запустить этот пример на Windows, создайте StringVector.lib
и StringVector.dll
файлы от этого StringVector.cpp
исходный файл, с помощью Примера Сборки Совместно использовал Файлы Библиотеки на Windows.
#define EXPORT #include "StringVector.hpp" DLL_EXPORT void readStringVector(const std::vector<std::string>& stringVector) { } DLL_EXPORT std::vector<std::string> getStringVector(int size) { std::vector<std::string> stringVector; for (int i = 0; i < size; i++) { stringVector.push_back(("string"+ std::to_string(i+1))); } return stringVector; }
Создайте StringVector.hpp
заголовочный файл и помещенный это с StringVector.dll
совместно использованный файл библиотеки в папке, идентифицированной как rtpath
.
Поддерживать std::vector
из типа std::string
, создайте CVector
класс, который задает эти методы, чтобы передать std::vector
между MATLAB и библиотекой.
Параметризованный конструктор:
CVector(const std::vector<T>& d): data(d)
Перемещение конструктора:
CVector(std::vector<T>&& d) : data(std::move(d))
Метод, чтобы получить доступ к элементу в индексе:
T get(int index)
Метод, чтобы добавить элементы в векторы:
void add(const T& element)
Метод, чтобы получить данные из векторов:
const std::vector<T>& getData() const
CVector.hpp
задает этот класс.
//Wrapper header to access/pass std::vector from MATLAB #ifndef cvector_header #define cvector_header #include <vector> template<typename T> class CVector { std::vector<T> data; public: CVector() {} CVector(const std::vector<T>& d): data(d) {} CVector(std::vector<T>&& d) : data(std::move(d)) {} T get(int index) { return data.at(index-1); } void add(const T& element) { data.push_back(element); } const std::vector<T>& getData() const { return data; } }; #endif
Включать readStringVector
и getStringVector
, создайте WrapperStringVector.hpp
заголовочный файл, который задает методы, чтобы передать CVector
аргументы к методам библиотеки C++.
// Header that allows the readStringVector and getStringVector functions // to be accessed from MATLAB interface #include "StringVector.hpp" #include "CVector.hpp" #include <string> void wrapperReadStringVector(const CVector<std::string>& stringVec) { readStringVector(stringVec.getData()); } CVector<std::string> wrapperGetStringVector(int size) { auto strVec = getStringVector(size); CVector<std::string> cvecString(strVec); return cvecString; }
Сгенерируйте определение библиотеки.
clibgen.generateLibraryDefinition(["StringVector.hpp","WrapperStringVector.hpp"],"PackageName","StringVector",... "Libraries","StringVector.lib","TreatObjectPointerAsScalar",true,"Verbose",true)
Создайте интерфейс.
build(defineWrapperStringVector)
addpath('WrapperStringVector')
Добавьте разделяемый путь к библиотеке к системе (время выполнения) путь. Если файл расположен на rtPath
, затем тип:
syspath = getenv('PATH'); rtPath = 'myrtpathname'; setenv('PATH',[rtPath ';' syspath]);
Вызовите функции.
% Instantiate the CVector class stringVectorObj = clib.StringVector.CVector_std____cxx11__basic_string_char_Std__char_traits_c; % Add elements to vector stringVectorObj.add("Jack"); stringVectorObj.add("John"); stringVectorObj.add("Joe"); % Call function with std::string vector input with CVector clib.StringVector.wrapperReadStringVector(stringVectorObj); clear stringVectorObj;
В командной строке Windows добавьте путь к компилятору MinGW-w64 к системному пути. Например, если компилятор в mingwpath
, затем тип:
mingwpath = 'mingwpathname'; set PATH=mingwpath;%PATH%
Перейдите к местоположению исходных файлов C++.
Запустите эти команды, чтобы сгенерировать совместно использованную библиотеку от исходного файла
:source
.cpp
mingwpath\g++ -c source.cpp -o source.obj -std=c++11 mingwpath\g++ -shared -o source.dll source.obj -Wl,--out-implib,source.lib