In the previous tutorial, we successfully developed a Flutter FFI plugin that compiles into a library, enabling us to generate a sine wave using GStreamer. We also created a Flutter application that calls the functions from this library. In this tutorial, we will focus on adapting this application to run on Windows.
This guide is tailored specifically for Windows, and all instructions will be provided accordingly.
Before you begin, make sure you have the following foundational knowledge:
Basic understanding of the C programming language.
Familiarity with Dart/Flutter.
Basic knowledge of CMake.
Basic knowledge of GStreamer.
For this tutorial, we will demonstrate on a Windows PC. The following tools and software are necessary:
GStreamer Libraries: Install GStreamer and its development libraries. Follow the GStreamer documentation for installation instructions.
Code Editor: You can use any code editor, but we will use Visual Studio Code (VSCode).
Flutter: Install Flutter by following the guidelines on the official Flutter website.
Visual Studio: Required for Flutter for Windows development. Download it from the official Visual Studio website.
CMake: Download from cmake.org. You can also install it through the Visual Studio installer on Windows.
To proceed, we need to install GStreamer and other dependencies. We will use Chocolatey, a package manager for Windows. Open a PowerShell window with administrative privileges and run the following command to install Chocolatey:
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
After Chocolatey is installed, run the following command to install GStreamer and Git:
choco install git gstreamer gstreamer-devel
This command will install the GStreamer runtime libraries as well as the development libraries. Note that we are also installing Git for version control.
First, open the app project in Visual Studio Code. Try running it, and you will likely encounter several errors leading to a build failure. To diagnose the issue, build the project in verbose mode by running:
flutter build windows -vvv --debug
You will see errors similar to the following:
[ +78 ms] LINK : warning LNK4044: unrecognized option '/LC:/gstreamer/1.0/msvc_x86_64/lib'; ignored
[C:\Users\username\Projects\flutter_gst\app\flutter_gst\build\windows\x64\plugins\native_binding\shared\native_binding.vcxproj]
[ +4 ms] LINK : warning LNK4044: unrecognized option '/lgstreamer-1.0'; ignored
[C:\Users\username\Projects\flutter_gst\app\flutter_gst\build\windows\x64\plugins\native_binding\shared\native_binding.vcxproj]
...
[ +1 ms] native_binding.obj : error LNK2019: unresolved external symbol g_thread_new, referenced in function run_mainloop
[C:\Users\username\Projects\flutter_gst\app\flutter_gst\build\windows\x64\plugins\native_binding\shared\native_binding.vcxproj]
...
The error messages indicate that the build is failing due to unrecognized options or unresolved symbols. One notable error is:
[ ] C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.40.33807\bin\HostX64\x64\link.exe /ERRORREPORT:QUEUE
/OUT:"C:\Users\fengj\Projects\fltgst\app\fltgst\build\windows\x64\plugins\native_binding\shared\Debug\native_binding.dll" /INCREMENTAL
/ILK:"native_binding.dir\Debug\native_binding.ilk" /NOLOGO "-LC:/gstreamer/1.0/msvc_x86_64/lib" "-lgstreamer-1.0" "-lgobject-2.0"
"-lglib-2.0" "-lintl" kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib
/MANIFEST /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /manifest:embed /DEBUG
/PDB:"C:/Users/fengj/Projects/fltgst/app/fltgst/build/windows/x64/plugins/native_binding/shared/Debug/native_binding.pdb"
/SUBSYSTEM:CONSOLE /TLBID:1 /DYNAMICBASE /NXCOMPAT
/IMPLIB:"C:/Users/fengj/Projects/fltgst/app/fltgst/build/windows/x64/plugins/native_binding/shared/Debug/native_binding.lib" /MACHINE:X64
/machine:x64 /DLL native_binding.dir\Debug\native_binding.obj
And we can see from the warning when linking the library LINK : warning LNK4044: 无法识别的选项“/LC:/gstreamer/1.0/msvc_x86_64/lib”;已忽略
, this error translates to "unrecognized option '/LC:/gstreamer/1.0/msvc_x86_64/lib'; ignored." This suggests that the pkg-config
output is using Unix-style options, which are not recognized by the MSVC linker on Windows.
CMakeLists.txt
for WindowsTo resolve these issues, we need to modify the CMakeLists.txt
to handle the options correctly for the MSVC environment. Follow these steps:
Open CMakeLists.txt
in the native_binding/src
directory.
Modify the script to use pkg-config
with MSVC syntax. Add the following code after pkg_search_module(GST REQUIRED gstreamer-1.0)
:
IF(WIN32)
find_program(CMAKE_PKGCONFIG_EXECUTABLE pkg-config)
IF(CMAKE_PKGCONFIG_EXECUTABLE)
# pkg-config.exe gstreamer-1.0 --libs --msvc-syntax
EXEC_PROGRAM(${CMAKE_PKGCONFIG_EXECUTABLE}
ARGS " --libs --msvc-syntax gstreamer-1.0"
OUTPUT_VARIABLE GST_LDFLAGS)
message("GST_LDFLAGS: ${GST_LDFLAGS}")
ENDIF()
ENDIF()
CMakeLists.txt
to use the generated GST_LDFLAGS
. Replace the existing target_link_libraries
line with the following:IF(WIN32)
target_link_options(native_binding PRIVATE ${GST_LDFLAGS})
ELSE()
target_link_libraries(native_binding PRIVATE ${GST_LDFLAGS})
ENDIF()
flutter pub get
and then flutter build windows -vvv --debug
.And we still got error when building:
[ +88 ms] native_binding.obj : error LNK2019: 无法解析的外部符号 g_thread_new,函数 run_mainloop 中引用了该符号
[C:\Users\fengj\Projects\fltgst\app\fltgst\build\windows\x64\plugins\native_binding\shared\native_binding.vcxproj]
[ +2 ms] native_binding.obj : error LNK2019: 无法解析的外部符号 g_main_loop_new,函数 setup_pipeline 中引用了该符号
[C:\Users\fengj\Projects\fltgst\app\fltgst\build\windows\x64\plugins\native_binding\shared\native_binding.vcxproj]
[ +1 ms] native_binding.obj : error LNK2019: 无法解析的外部符号 g_main_loop_run,函数 run_main_loop_thread 中引用了该符
号
[C:\Users\fengj\Projects\fltgst\app\fltgst\build\windows\x64\plugins\native_binding\shared\native_binding.vcxproj]
[ +1 ms] native_binding.obj : error LNK2019: 无法解析的外部符号 g_main_loop_unref,函数 run_mainloop 中引用了该符号
[C:\Users\fengj\Projects\fltgst\app\fltgst\build\windows\x64\plugins\native_binding\shared\native_binding.vcxproj]
[ +1 ms] native_binding.obj : error LNK2019: 无法解析的外部符号 g_main_loop_is_running,函数 run_mainloop 中引用了该符
号
[C:\Users\fengj\Projects\fltgst\app\fltgst\build\windows\x64\plugins\native_binding\shared\native_binding.vcxproj]
[ +1 ms] native_binding.obj : error LNK2019: 无法解析的外部符号 g_printerr,函数 setup_pipeline 中引用了该符号
[C:\Users\fengj\Projects\fltgst\app\fltgst\build\windows\x64\plugins\native_binding\shared\native_binding.vcxproj]
[ +4 ms] native_binding.obj : error LNK2019: 无法解析的外部符号 g_type_check_instance_cast,函数 setup_pipeline 中引用
了该符号
[C:\Users\fengj\Projects\fltgst\app\fltgst\build\windows\x64\plugins\native_binding\shared\native_binding.vcxproj]
[ +13 ms] native_binding.obj : error LNK2019: 无法解析的外部符号 __imp_gst_object_unref,函数 setup_pipeline 中引用了该
符号
[C:\Users\fengj\Projects\fltgst\app\fltgst\build\windows\x64\plugins\native_binding\shared\native_binding.vcxproj]
[ +3 ms] native_binding.obj : error LNK2019: 无法解析的外部符号 __imp_gst_element_factory_make,函数 setup_pipeline 中
引用了该符号
[C:\Users\fengj\Projects\fltgst\app\fltgst\build\windows\x64\plugins\native_binding\shared\native_binding.vcxproj]
[ +1 ms] native_binding.obj : error LNK2019: 无法解析的外部符号 __imp_gst_element_set_state,函数 start_pipeline 中引用
了该符号
[C:\Users\fengj\Projects\fltgst\app\fltgst\build\windows\x64\plugins\native_binding\shared\native_binding.vcxproj]
[ +1 ms] native_binding.obj : error LNK2019: 无法解析的外部符号 __imp_gst_bin_get_type,函数 setup_pipeline 中引用了该
符号
[C:\Users\fengj\Projects\fltgst\app\fltgst\build\windows\x64\plugins\native_binding\shared\native_binding.vcxproj]
[ +3 ms] native_binding.obj : error LNK2019: 无法解析的外部符号 __imp_gst_pipeline_new,函数 setup_pipeline 中引用了该
符号
[C:\Users\fengj\Projects\fltgst\app\fltgst\build\windows\x64\plugins\native_binding\shared\native_binding.vcxproj]
[ +2 ms] native_binding.obj : error LNK2019: 无法解析的外部符号 __imp_gst_element_link_many,函数 setup_pipeline 中引用
了该符号
[C:\Users\fengj\Projects\fltgst\app\fltgst\build\windows\x64\plugins\native_binding\shared\native_binding.vcxproj]
[ +2 ms] native_binding.obj : error LNK2019: 无法解析的外部符号 __imp_gst_bin_add_many,函数 setup_pipeline 中引用了该
符号
[C:\Users\fengj\Projects\fltgst\app\fltgst\build\windows\x64\plugins\native_binding\shared\native_binding.vcxproj]
[ +4 ms] native_binding.obj : error LNK2019: 无法解析的外部符号 __imp_gst_init,函数 init 中引用了该符号
[C:\Users\fengj\Projects\fltgst\app\fltgst\build\windows\x64\plugins\native_binding\shared\native_binding.vcxproj]
[ +1 ms]
C:\Users\fengj\Projects\fltgst\app\fltgst\build\windows\x64\plugins\native_binding\shared\Debug\native_binding.dll :
fatal error LNK1120: 15 个无法解析的外部命令
[C:\Users\fengj\Projects\fltgst\app\fltgst\build\windows\x64\plugins\native_binding\shared\native_binding.vcxproj]
And again, few lines above, we find the command that caused the error:
[ +1 ms] C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.40.33807\bin\HostX64\x64\link.exe
/ERRORREPORT:QUEUE
/OUT:"C:\Users\fengj\Projects\fltgst\app\fltgst\build\windows\x64\plugins\native_binding\shared\Debug\native_binding.dll"/INCREMENTAL /ILK:"native_binding.dir\Debug\native_binding.ilk" /NOLOGO kernel32.lib user32.lib gdi32.lib winspool.lib
shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib /MANIFEST /MANIFESTUAC:"level='asInvoker'
uiAccess='false'" /manifest:embed /DEBUG
/PDB:"C:/Users/fengj/Projects/fltgst/app/fltgst/build/windows/x64/plugins/native_binding/shared/Debug/native_binding.pdb"/SUBSYSTEM:CONSOLE /TLBID:1 /DYNAMICBASE /NXCOMPAT
/IMPLIB:"C:/Users/fengj/Projects/fltgst/app/fltgst/build/windows/x64/plugins/native_binding/shared/Debug/native_binding.lib" /MACHINE:X64 /machine:x64 "/libpath:C:/gstreamer/1.0/msvc_x86_64/lib gstreamer-1.0.lib gobject-2.0.lib glib-2.0.lib
intl.lib" /DLL native_binding.dir\Debug\native_binding.obj
Pay attention to the last two argument, you will see a double quote, and when you find the start of that double quote, it's from the GST_LDFLAGS
we generated from pkg-config
! And my guess is, the double quote makes the linker thinks the entire object inside the double quote is a single option, which is not what we want, so we need to find a way to get rid of the double quote.
Luckly, microsoft has drop some hint on what we can do:
https://learn.microsoft.com/en-us/cpp/build/reference/linking?view=msvc-170#link-environment-variables :
TheLIB
variable can contain one or more path specifications, separated by semicolons. One path must point to the\lib
subdirectory of your Visual C++ installation.
So we replace the white space with a semicolon.
Head back to native_binding/lib/CMakeListst.txt
, and add some text to the first IF(WIN32)
block, so it look like this:
...
IF(WIN32)
find_program(CMAKE_PKGCONFIG_EXECUTABLE pkg-config)
IF(CMAKE_PKGCONFIG_EXECUTABLE)
# pkg-config.exe gstreamer-1.0 --libs --msvc-syntax
EXEC_PROGRAM(${CMAKE_PKGCONFIG_EXECUTABLE}
ARGS " --libs --msvc-syntax gstreamer-1.0"
OUTPUT_VARIABLE GST_LDFLAGS)
# replace spaces with semicolons so that we don't have quotation marks in command line option
string(REPLACE " " ";" GST_LDFLAGS ${GST_LDFLAGS})
message("GST_LDFLAGS: ${GST_LDFLAGS}")
ENDIF()
ENDIF()
...
After making the changes, update the dependencies in your app project and rebuild it:
Update the dependencies:
flutter pub get
Build the project:
flutter build windows -vvv --debug
And the build success:
[ +40 ms] Building Windows application... (completed in 15.6s)
[ +5 ms] √ Built build\windows\x64\runner\Debug\fltgst.exe
[ +2 ms] "flutter windows" took 16,516ms.
[ +274 ms] ensureAnalyticsSent: 267ms
[ +1 ms] Running 0 shutdown hooks
[ ] Shutdown hooks complete
[ ] exiting with code 0
Run the app, and you should hear the sine wave.
Just like before, but add the following too configurations
in .vscode/launch.json
file:
{
"name":"Windows native",
"type":"cppvsdbg",
"request": "launch",
"program": "${workspaceRoot}/build/windows/runner/Debug/fltgst.exe",
"cwd": "${fileDirname}",
},
By following this tutorial, you have adapted a Flutter FFI plugin to work on a Windows platform, including handling the specific requirements of the MSVC linker. Ensure you follow each step carefully to resolve any build issues, and consult the GStreamer and Flutter documentation for further troubleshooting tips. Happy coding!
Find the repository and files updated in this tutorial at:
Repository: https://github.com/fengjiongmax/fltgst
Files after changes: https://github.com/fengjiongmax/fltgst/tree/199f63aa6915ce8ad1f489af6ea536c4404fbfc2