0

I'm trying to write a c++ library to extend some features for my flutter project using dart ffi. I use Cmake as the build tool for c++. On Android this works really well, because I don't need the full path to the library. But if I build my app on Windows the dll file isn't in the same directory as the executable and I have to use some weird relative paths. I also want to have the debug and release files in the corresponding directories.

I have added in the CMakeLists.txt in the windows directory my library as a subdirectory. In the CMakeLists.txt of my library I tried to use set(CMAKE_LIBRARY_OUTPUT_DIRECTORY $<Target_file_dir:${BINARY_NAME}> and get_property(bin_dir TARGET ${BINARY_NAME} PROPERTY LOCATION). It seems linke cmake ignores the output directory property. Is there another way to get the Flutter runtime directory, even if I use my Flutter project as a package for another project? I wouldn't be a problem, if I just run a .bat file to move all the dlls after build.

itsLeatch
  • 1
  • 1

1 Answers1

-1

I've done a little research and here is a full example with media_kit plugin.

1. Go to your project, open "Windows" folder and find CMakeLists.txt file. 2. Open this file and find these two lines:

set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}")

and change them to this:

set(INSTALL_BUNDLE_LIB_SUBDIR "media_kit") # Here you can choose any name for the folder where all dlls from this package will be located
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/${INSTALL_BUNDLE_LIB_SUBDIR}")

# Delay main plugin dlls loading to avoid "The code execution cannot proceed because ...dll was not
# found" error
target_link_options(${BINARY_NAME} PRIVATE "/DELAYLOAD:screen_brightness_windows_plugin.dll")
target_link_options(${BINARY_NAME} PRIVATE "/DELAYLOAD:media_kit_libs_windows_video_plugin.dll")
target_link_options(${BINARY_NAME} PRIVATE "/DELAYLOAD:media_kit_video_plugin.dll")

3. Find this two line of code in the same file:

install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
  COMPONENT Runtime)

and replace them with this:

install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${CMAKE_INSTALL_PREFIX}"
  COMPONENT Runtime)

This code will make sure that flutter_windows.dll is located at the same folder where your main executable is being compiled 4. Scroll down to the last line in this file and add there the following code:

# Copy main flutter dlls from [https://docs.flutter.dev/platform-integration/windows/building]
# to the same folder where app's executable is located. Remove dlls from their original source path
# after copying.
set(SOURCE_FILES
  "${CMAKE_CURRENT_BINARY_DIR}/runner/Release/${INSTALL_BUNDLE_LIB_SUBDIR}/msvcp140.dll"
  "${CMAKE_CURRENT_BINARY_DIR}/runner/Release/${INSTALL_BUNDLE_LIB_SUBDIR}/api-ms-win-crt-runtime-l1-1-0.dll"
  "${CMAKE_CURRENT_BINARY_DIR}/runner/Release/${INSTALL_BUNDLE_LIB_SUBDIR}/vcruntime140.dll"
  "${CMAKE_CURRENT_BINARY_DIR}/runner/Release/${INSTALL_BUNDLE_LIB_SUBDIR}/vcruntime140_1.dll"
)
install(CODE "
  execute_process(COMMAND ${CMAKE_COMMAND} -E copy ${SOURCE_FILES} ${CMAKE_CURRENT_BINARY_DIR}/runner/Release)
  file(REMOVE ${SOURCE_FILES})
")

5. Navigate to Windows/runner/main.cpp and add this method below all includes

// Tries to add provided path to the set of directories that are searched for a DLL
void _addFolderToLookable(std::wstring path) {
  // Construct the path to the binaries folder
  std::wstring dllDirectory = path + L"\\" + L"media_kit";
  SetDllDirectoryW(dllDirectory.c_str());
}

then add the following code to the beginning of wWinMain method:

  // Add path to [INSTALL_BUNDLE_LIB_SUBDIR] variable from CMake so that all /DELAYLOAD dlls
  // can be loaded
  WCHAR exePath[MAX_PATH];
  DWORD pathLength = GetModuleFileName(0, exePath, MAX_PATH);
  if (pathLength != 0 && !std::wstring(exePath).empty()) {
    // Extract the directory path from the executable path
    std::wstring exeDirectory = exePath;
    size_t lastSeparator = exeDirectory.find_last_of(L"\\/");
    exeDirectory = exeDirectory.substr(0, lastSeparator + 1);

    _addFolderToLookable(exeDirectory);
  } else {
    // Try one more way of retrieving current app's folder
    pathLength = GetCurrentDirectory(MAX_PATH, exePath);
    if (pathLength != 0) {
      std::wstring exeDirectory = exePath;
      if(!exeDirectory.empty()) _addFolderToLookable(exeDirectory);
    }
  }

Make sure #include <windows.h> and #include <psapi.h> are included at the top of the file.

Result: All default flutter dlls are located near the main executable and all plugin dlls can be found in media_kit directory. This methods supports all windows versions from 7 to 11. image

Kirill
  • 1,129
  • 1
  • 7
  • 16